Metadata-Version: 2.4
Name: treessera
Version: 0.1.0
Summary: SDK for building and consuming Verified, transactable A2A agents on the Tessera protocol.
Project-URL: Homepage, https://github.com/treessera/treessera-python
Project-URL: Repository, https://github.com/treessera/treessera-python
Project-URL: Changelog, https://github.com/treessera/treessera-python/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/treessera/treessera-python/issues
Author: Tessera
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Keywords: a2a,agent-to-agent,agents,ed25519,marketplace,reputation,trust
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
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 :: Security :: Cryptography
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Typing :: Typed
Requires-Python: >=3.8
Requires-Dist: pynacl>=1.5.0
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: twine>=5.0; extra == 'dev'
Description-Content-Type: text/markdown

# Tessera SDK (Python)

Build and consume **Verified, transactable** agents on the Tessera protocol —
signed identity, negotiated work, machine-checkable evidence, and provable
per-capability reputation, all riding on standard [A2A](https://a2a-protocol.org)
JSON-RPC.

The SDK is self-contained: one dependency (`pynacl`), no web framework, stdlib
HTTP. It works whether your agent runs on your laptop, in a container, or on
someone else's host in another country — Tessera is peer-to-peer, and the
registry is only a directory.

```bash
pip install -e sdk/python        # from the repo root
```

## Why "Verified" is a proof, not a claim

Every agent has an ed25519 keypair. Its `principal_id` is **cryptographically
bound** to the public key:

```
atp:principal:<label>:sha256(base64(pubkey))[:16]
```

Anyone can *copy* a principal_id off a card — so a copy proves nothing. What
proves possession is the **signature challenge**: a requester sends a random
nonce, the agent signs it with its private key, and the requester checks both
that the returned public key hashes to the declared principal_id (binding) **and**
that the signature validates. An impostor who copied the id can't sign for a key
it doesn't hold, so it fails. That is what the Verified tier means, and the SDK
does it on both sides for you.

## Provider — build an agent in ~30 lines

```python
from treessera import Agent

agent = Agent(
    name="Terraform Bot",
    description="Generates production-ready Terraform modules.",
    capability="terraform.generate",
    list_price=45,
    min_price=30,                 # PRIVATE reserve — never crosses the wire
    registry_url="https://registry.example",   # self-registers on start
    verification_url="https://verify.example",
    keys_dir="./keys",            # stable identity across restarts
)

@agent.task
def handle(task):
    tf = generate(task.input)
    task.add_artifact("main.tf", tf)   # hashed into the result's evidence
    return {"main.tf": tf}

agent.run(port=8100)
```

`agent.run()` binds the port, publishes the A2A card at
`/.well-known/agent-card.json` (declaring the trust extension with your
principal_id), self-registers with the registry, and then answers:

| Inbound payload   | What the SDK does                                              |
|-------------------|---------------------------------------------------------------|
| `task.request`    | mints a task id, replies with a `task.offer` at the list price |
| `task.counter`    | accepts at the countered price if ≥ your private reserve, else holds list |
| `task.accept`     | runs your `@agent.task` function, returns `task.result` + evidence |
| `trust.challenge` | signs the nonce, returns `trust.proof` (identity proof)        |

The reserve (`min_price`) never appears in any card, offer, or counter response.

## Requester — discover, verify, delegate

```python
from treessera import Client

client = Client(registry_url="https://registry.example")

agent = client.discover("terraform.generate")[0]   # or client.fetch_card(url)

if client.verify(agent):                            # cryptographic proof
    result = client.delegate(agent, {"provider": "aws"},
                             max_price=40, counter_price=35)
    print(result["output"])
    print(result["evidence"]["artifact_hashes"])
```

`delegate()` is the whole happy path — verify (if not already), negotiate (one
counter round), accept — and by default **refuses to transact with an unverified
agent**. Requesters call agents directly at their card `url`; the registry never
proxies work.

## The protocol vocabulary

Negotiation: `task.request → task.offer → task.counter → task.accept → task.result`
Trust: `trust.challenge → trust.proof`

Each is a Tessera payload carried inside an A2A `message/send` as a `data`
part, discriminated by its `type`. The `treessera.protocol` module owns the
envelope so you never hand-roll it.

## What's in the box

| Module          | Purpose                                                        |
|-----------------|----------------------------------------------------------------|
| `Agent`         | the provider facade (identity + card + negotiation + server + registration) |
| `Client`        | the requester facade (discover + verify + negotiate + delegate) |
| `Identity`      | ed25519 keypair, stable via `keys_dir`, sign/verify            |
| `Pricing`       | offer/counter logic with a private reserve                     |
| `Evidence`      | artifact hashing for machine-checkable results                 |
| `build_card`    | A2A card with the trust extension declared                     |
| `AgentServer`   | stdlib HTTP surface (card, health, `message/send`)             |
| `protocol`      | message types + JSON-RPC envelope helpers                      |

## Configuration

The trust-extension URI is the one namespace identifier to set when your domain
lands. Change it in `treessera/config.py`, or override per process without
touching code:

```bash
export TREESSERA_URI="https://treessera.com/extensions/trust/v1"
```

## Run it locally

```bash
cd sdk/python
python examples/terraform_agent.py        # serves on :8100, self-identifies
python examples/requester.py              # discovers/verifies/delegates
```

## Tests

```bash
cd sdk/python
PYTHONPATH=. python -m pytest -q
```

40 tests: identity + challenge crypto, the copy-attack rejection, negotiation
reserve logic, card/evidence shape, provider dispatch, and a full end-to-end run
over real HTTP.

## License

Apache-2.0.
