Metadata-Version: 2.5
Name: prismnetwork
Version: 0.4.1
Summary: Headless GPU leasing and metered confidential inference on Prism Network for autonomous agents. Wallet-signature auth, on-chain USDG payment, SSH.
Project-URL: Homepage, https://prismnetwork.tech
Project-URL: Source, https://github.com/prismnetwork-tech/prism
License-Expression: Apache-2.0
Keywords: agent,gpu,llm,prism,usdg,web3
Requires-Python: >=3.10
Requires-Dist: cryptography>=42.0
Requires-Dist: eth-account>=0.11
Requires-Dist: requests>=2.31
Requires-Dist: web3>=6.0
Provides-Extra: confidential
Requires-Dist: dcap-qvl>=0.6.3; extra == 'confidential'
Requires-Dist: pyjwt[crypto]>=2.8; extra == 'confidential'
Description-Content-Type: text/markdown

# prismnetwork

Headless GPU leasing on [Prism Network](https://prismnetwork.tech) for autonomous
agents, the Python counterpart to `@prismnetwork/agent-sdk`. Give it a wallet; it
authenticates with a signature, pays on-chain in USDG, provisions a GPU, and runs
over SSH. No browser, no dashboard.

```sh
pip install prismnetwork
```

```python
from prismnetwork import PrismAgent, DEFAULT_IMAGE

agent = PrismAgent(private_key=AGENT_KEY, escrow="0xfD4228eEEfC49e4b76A0CD40af9fdd546220B2FD")
agent.authenticate()

lease = agent.lease(image=DEFAULT_IMAGE, duration_seconds=600, min_vram_mib=16000)
out = agent.run(lease, "nvidia-smi")
print(out["stdout"])
agent.end_lease(lease)
```

## What it does

`authenticate()` signs a challenge with the wallet and exchanges it for a bearer
session. `lease()` gets a quote, funds an on-chain USDG escrow bound to the quote
(`createLease`), waits for the GPU to provision, and returns SSH access. `run()`
executes a command over SSH, retrying through the host's sshd warmup. `end_lease()`
releases the machine, and the release is what stops the meter: settlement charges
the seconds between access opening and the release and returns the rest of the
deposit, with a receipt on chain. A lease nobody releases bills until its window
ends.

To show the price to a human before any money moves, take the two halves
separately: `quote(...)` returns the machine, rate and maximum deposit, and
`fund_quote(quote)` funds exactly that quote and waits for access. A quote lives
five minutes; one that has expired is refused at funding rather than replaced.

Read-only helpers: `offers()`, `balances()`, `leases()`, `access(id)`.

## Which machine answered

Every session `run()` opens checks the SSH host key on the far end, and
`host_key_policy(lease.access)` says what that check was worth:

```python
from prismnetwork import host_key_policy

host_key_policy(lease.access)
# {"mode": "attested" | "reported" | "unverified", "fingerprint": ..., "source": ...}
```

`attested` means the fingerprint comes out of a hardware report whose signed data
commits to the key the guest generated at boot. Prism walks that report and puts
the fingerprint on the access grant, and the SDK refuses a session whose host key
does not match it, so the operator cannot put a different machine on the other
end. The report is checked in our control plane rather than here, so `attested`
says we checked it and this client holds the session to what we published.

`reported` means the node named the key on the signed report that opened
access, which rules out the relay and the network path but not the operator,
whose bond is what a dispute reaches instead.

`unverified` means nobody published a key: capacity brokered from a public
cloud has its host key generated by the cloud and never shown to the network, so
the key is recorded on first sight and held for the rest of the lease.

Your own `~/.ssh/known_hosts` is never touched. The record sits beside the
lease's private key and is removed with it by `end_lease()`, which also releases
the lease on the network so billing stops there instead of at the end of the
window.

`PrismAgent(..., require_host_key=True)` refuses to open a session on a lease
that publishes no key, rather than trusting whichever machine answers first.

## Batch

Pass `command=` to `lease()` and the node runs that one command and reports its
output instead of granting SSH access:

```python
batch = agent.lease(image=DEFAULT_IMAGE, duration_seconds=600, command="nvidia-smi")
print(batch.result["stdout"])
```

Batch leases match only suppliers at trust class `isolated` or above, because the
broker path has no signed result channel. Commands are capped at 8 KiB and output
at 64 KiB per stream. `result(lease_id)` and `wait_for_result(lease_id)` read the
output of an already-funded batch lease.

## Inference

Buy one generation without renting anything. The endpoint owns the GPU and the
wallet pays per call.

```python
run = agent.infer(prompt="explain metered GPU compute", max_usdg=0.05)
print(run["text"], run["tx"])
```

The supplier running that GPU can read the prompt and the answer.

A 200 whose body is not a completion is handed back whole: `text` is `None` and
`response` holds what the endpoint served. A body that is not JSON at all raises
`PaymentError` with code `malformed_answer`, naming the transfer that bought it.

## Confidential inference

`confidential_infer()` buys a generation from a model running in a GPU TEE. The
prompt is encrypted to a key the enclave's hardware quote commits to, and that
quote is checked before anything leaves this process: it has to verify to Intel's
root, commit to the key set the prompt will be sealed to, and measure the code
this SDK pins. A check that does not hold raises `ConfidentialError` and no
prompt is sent. There is no fallback to the open tier.

```python
from prismnetwork import render_checks

run = agent.confidential_infer(prompt="what is my position worth")
print(run["text"])
print(render_checks(run["verify"]()))
```

Verifying a quote to Intel's root needs the DCAP verifier:
`pip install 'prismnetwork[confidential]'`. Without it the call refuses rather
than sending a prompt to hardware nothing has checked.

`agent.verify_confidential(run)`, also reachable as `run["verify"]()`, re-checks
the exchange after the fact against the exact bytes sent and received: the receipt
the workload signed over them, and the attestation behind the key set they were
sealed to. Pass `verify_gpu=True` to the call to additionally tie NVIDIA's GPU
evidence to the same TD before the prompt is sent.

## Spending limits

Everything that spends reads and writes one ledger, so a wallet has one ceiling
however many clients hold it.

```sh
PRISM_MAX_USDG=1            # a single lease or generation
PRISM_DAILY_BUDGET_USDG=5   # a rolling 24 hours
PRISM_LEDGER_PATH=~/.prism/spend.json
```

`PrismToolset` enforces both, and `budget_status()` reports what is in force and
what the last 24 hours cost. A `max_usdg` the model supplies lowers the
operator's per-call cap for one call and can never raise it. The charge is
committed before the money moves: an attempt that never reached the chain hands
its reservation back, and one that funded an escrow keeps its entry and gains the
transaction that proves it. `read_budget()`, `SpendLedger` and `record_spend()`
are the same pieces for a caller wiring its own tools.

## What a lease cost

`lease.deposit_micros` is what the escrow pulled, read from the `LeaseFunded` log
of the funding transaction. The quote's `maximum_escrow` is a ceiling: the escrow
charges rate per second times duration and leaves the rest in the wallet.
`lease.deposit_source` is `"receipt"` for the figure off the log, and `"quote"`
for the ceiling, which stands in only when there is no log to read.

## What a failure says about your money

Every `PrismError` places itself on one side of the send. `broadcast` is `False`
when nothing reached the chain and the transaction hash when something did.

A failure after a payment settled carries that hash in `broadcast` and in
`body["payment_tx"]`, including one raised while the answer was being read, so a
ledger settles against the transfer instead of reverting money that has moved.
`PaymentError.body["payment_header"]` redeems a settled payment the endpoint
never served, and only for the exact request it was signed over.

## Paying an x402 endpoint

Prism's pay-per-call endpoints take a transfer plus a signature over what the
transfer buys, so a payment can only be redeemed against the request it was made
for. `payment_header` builds the `X-PAYMENT` value:

```python
from prismnetwork import payment_header

body = json.dumps({"model": "llama3.2:3b", "prompt": "what is a prism"}).encode()
header = payment_header(agent.account, tx_hash, body)
```

Pass the bytes the request actually carries. `bound_message` and `hash_request`
are exported for a client that builds the envelope itself; they produce the same
message the Node SDK signs.

The wallet needs USDG (`0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168`, 6 decimals) and
native Robinhood-Chain gas.

Requires `ssh`, `ssh-keygen` and `ssh-keyscan` on `PATH`. Chain id 4663, RPC
`https://rpc.mainnet.chain.robinhood.com`.

Prism is pre-production and unaudited. A permissionless supplier is not a trusted
computing environment; do not lease with a wallet or workload you cannot lose.
