Python SDK Integration
PyHall Python SDK
Add WCP governance to any Python application. One make_decision() call wraps any worker capability in the full governance chain: registration, attestation, policy evaluation, ban list check, and audit record.
Installation
pip install pyhall-wcpWhat you can do
- Register workers — give AI agents verified identities with capability declarations
- Make routing decisions — check authorization before every capability execution
- Verify attestation — confirm a worker’s signed capability card is valid and unrevoked
- Enforce policy tiers — apply WCP risk controls (L0–L8) to every invocation
- Query audit history — inspect every ALLOW/DENY decision with timestamps and worker IDs
- Manage namespaces — claim and check
x.*community ororg.<name>.*org namespaces
Quick start
import osfrom pyhall import Hall
hall = Hall(api_key=os.environ["PYHALL_API_KEY"])
# Register a workerworker = hall.workers.register( name="my-agent", namespace="x.myagent", capabilities=["cap.data.read.v1", "cap.report.generate.v1"], policy_tier=2,)print(worker.id) # wrk_abc123print(worker.namespace) # x.myagent
# Make a routing decision before executing a capabilitydecision = hall.decisions.make( worker_id=worker.id, capability="cap.data.read.v1", env="dev", data_label="PUBLIC", tenant_id="org.acme",)
if decision.denied: raise PermissionError(f"Denied: {decision.deny_reason}")
# Safe to proceed — worker is authorizedresult = run_my_capability()print(decision.proof) # cryptographic proof hash for auditWrapping any function with governance
import functoolsfrom pyhall import Hall
hall = Hall(api_key=os.environ["PYHALL_API_KEY"])
def governed(capability: str, worker_id: str): """Decorator that gates any function behind a pyhall routing decision.""" def decorator(fn): @functools.wraps(fn) def wrapper(*args, **kwargs): decision = hall.decisions.make( worker_id=worker_id, capability=capability, env=os.environ.get("PYHALL_ENV", "dev"), data_label="PUBLIC", ) if decision.denied: raise PermissionError( f"pyhall denied {capability} for {worker_id}: {decision.deny_reason}" ) return fn(*args, **kwargs) return wrapper return decorator
@governed("cap.data.read.v1", worker_id="wrk_abc123")def fetch_sensitive_data(query: str) -> dict: # Only runs when pyhall says ALLOW return {"rows": [...]}FastAPI middleware example
from fastapi import FastAPI, Request, HTTPExceptionfrom pyhall import Hall
app = FastAPI()hall = Hall(api_key=os.environ["PYHALL_API_KEY"])
@app.middleware("http")async def pyhall_governance(request: Request, call_next): worker_id = request.headers.get("X-Worker-ID") capability = request.headers.get("X-Capability")
if worker_id and capability: decision = hall.decisions.make( worker_id=worker_id, capability=capability, env="prod", data_label="INTERNAL", ) if decision.denied: raise HTTPException(status_code=403, detail=decision.deny_reason)
return await call_next(request)Checking worker attestation
attest = hall.workers.attest(worker_id="wrk_abc123")
print(attest.status) # "attested" | "pending" | "denied"print(attest.artifact_hash) # SHA-256 of the attested worker packageprint(attest.attested_at) # ISO timestamp
if attest.status != "attested": raise RuntimeError("Worker is not attested — refusing to proceed")Querying decision history
history = hall.decisions.query(worker_id="wrk_abc123", limit=20)
for d in history.decisions: status = "ALLOW" if not d.denied else f"DENY ({d.deny_reason})" print(f"{d.decided_at} {d.capability_id} → {status}")Local Hall Server (Hall Monitor)
When Hall Monitor is running locally on port 8765:
import os, requests
token = os.environ["HALL_SESSION_TOKEN"]url = os.environ.get("HALL_SERVER_URL", "http://localhost:8765")
resp = requests.post( f"{url}/api/route", headers={"Authorization": f"Bearer {token}"}, json={ "capability_id": "cap.data.read.v1", "worker_id": "wrk_abc123", "env": "dev", "data_label": "PUBLIC", "tenant_id": "org.acme", }, timeout=5,)resp.raise_for_status()decision = resp.json()
if decision["denied"]: raise PermissionError(decision.get("deny_reason", "Denied by pyhall"))Environment variables
PYHALL_API_KEY=your-api-key # registry authentication (required)PYHALL_REGISTRY=https://api.pyhall.dev # default registry URL (override for self-hosted)PYHALL_NAMESPACE=x.myorg # default namespace for new worker registrationsPYHALL_ENV=dev # environment tag (dev | staging | prod)HALL_SESSION_TOKEN=your-token # local Hall Server auth (Hall Monitor)HALL_SERVER_URL=http://localhost:8765 # local Hall Server URLGetting started
# 1. Installpip install pyhall-wcp
# 2. Authenticatepyhall auth login
# 3. Claim a namespacepyhall namespace check x.yourname
# 4. Register your first workerpyhall worker register
# 5. Make a governed decisionpyhall decision make --worker <id> --cap cap.data.read.v1Full documentation: https://pyhall.dev/docs/reference/python/ WCP specification: https://workerclassprotocol.dev/spec/