Python SDK for the TunnelMind PIP — the Policy Information Point for the agentic internet. Four lenses, one signed, coverage-honest answer to "who is this node, really?"
The client verifies the PIP. Every response carrying a signed receipt is checked locally (Ed25519 + RFC 8785 canonical JSON) before you read it — you never have to take TunnelMind's word for TunnelMind. Cross-language conformance with the reference TypeScript verifier is pinned by a shared signed test vector.
pip install tunnelmindfrom tunnelmind import TunnelMind
tm = TunnelMind(api_key=os.environ.get("TUNNELMIND_API_KEY")) # key optional — free tier works anonymously
# Full 4-lens resolve (~2s) — preflight / out-of-band
bundle = tm.verify("example.com")
bundle["cross_lens"]["verdict"] # 'pass' | 'warn' | 'fail'
bundle["receipt_verification"]["valid"] # verified on your machine
# PDP hot path (<100ms edge-cached) — per-request authz loops
attrs = tm.attributes("example.com")
if attrs is None:
... # never verified (or aged past stale_if_error) — an honest miss, your policy decides
# "Should I act?" — allow / caution / deny + signed consultation receipt
pf = tm.preflight("example.com", intent="bid.submit")Standalone offline verification of any receipt:
from tunnelmind import verify_receipt
result = verify_receipt(receipt) # fetches the well-known key bundle + revocations (cached)
result = verify_receipt(receipt, no_fetch_keys=True, no_fetch_revocations=True) # fully offline
result.valid, result.errors, result.warnings| Field | Meaning |
|---|---|
cross_lens.verdict / trust_score |
the fused verdict, 0–1 |
coverage.rollup |
per-lens observed_clean / never_observed / degraded — observation vs honest blind spot vs failure |
coverage.valid_until / stale_if_error |
refresh after / how long a stale answer beats failing closed |
receipt_verification |
attached by this SDK — offline Ed25519 check of the receipt |
A failed local check never raises — the API answer is still the answer;
receipt_verification["errors"] is there for your policy to act on. Opt out
with local_verify=False (but that removes the point).
Two, both for verification, none for transport (stdlib urllib):
cryptography (Ed25519) and
rfc8785 (canonical JSON — deliberately
a dependency, not hand-rolled: ES6-compatible number serialization is exactly
the kind of edge-case minefield a signature scheme must not get subtly wrong).
Python ≥3.9. License: Apache-2.0.