Telemetry & Privacy
PyHall is explicit about what stays in your system and what touches the registry. This page is the complete record — no fine print.
What stays local — always
The following never leaves your infrastructure:
| Data | Where it lives |
|---|---|
| Capability requests | Your agent’s process |
| Routing decisions (which worker, why) | Your Hall Server / Hall Monitor |
| Decision deny reasons | Your evidence log |
| Agent identity and context | Your system |
| Tenant IDs | Your system |
| Policy configurations | Your system |
| Routing rules | Your system |
| Worker business logic output | Your system |
| Any data the worker processes | Your system |
make_decision() is a pure local function. It reads from an in-memory cache and returns a decision. No network call, no outbound data, no exceptions.
What touches the registry — on a 60-second cycle
Two calls happen during prefetch(), which runs on a background timer (default: every 60 seconds):
1. Standing receipt — GET /api/v1/verify/:worker_id
Sent: worker ID (e.g. org.example.my-worker or x.yourname.my-worker)
Received: attestation status, current registered hash, ban status
Purpose: Confirm the worker is still attested and not on the community ban list before the next decision window
One request per enrolled worker, per 60-second window. If you have 5 enrolled workers, that is 5 HTTP GETs per minute.
2. Decision count — POST /api/v1/telemetry/decisions
Sent:
{ "decisions": [ { "worker_id": "org.example.my-worker", "count": 847 } ]}Purpose: Aggregate count of how many routing decisions were issued to each worker in the last 60-second window. This is how the pyhall.dev network stats (“total routing decisions”) are computed.
What is NOT in this payload:
- No request content
- No agent data
- No tenant identifiers
- No user data
- No decision outcomes or reasons
- No IP addresses (CF Worker strips them from the stored record)
Only: worker ID + integer count.
What happens at startup — once
Package attestation — local only
PackageAttestationVerifier runs at Hall Server startup. It:
- Reads
manifest.jsonfrom disk - Computes a SHA-256 hash of the package files
- Compares against the manifest’s
package_hash - Verifies the HMAC-SHA256 signature against
WCP_ATTEST_HMAC_KEY
No network call. Entirely local. If attestation fails, the process exits — it does not phone home.
Account requirement
Using pyhall requires a pyhall.dev account in good standing. The standing receipt and decision count flush are mandatory parts of that integration — they are not configurable or disableable.
| Mode | Account required | Registry calls |
|---|---|---|
| Hall Monitor + registry | Yes — must be in good standing | Standing receipt + decision counts every 60s |
| Pure SDK (no registry, no Hall Monitor) | No | None — routes entirely from local data |
The pure SDK mode is the open source path — the Python, TypeScript, and Go SDKs are Apache 2.0 licensed and can be embedded in your own infrastructure without connecting to pyhall.dev. The WCP routing engine (make_decision(), rules, PolicyGate) is the same engine that powers the full product. What you don’t get without an account: namespace ownership, registry attestation, Hall Monitor, and the standing receipt chain. Hall (Hall Monitor + Hall API server) is a commercial application — not open source.
Registry data retention
Decision counts and verify hits are stored per worker ID per calendar day. No personally identifiable information is stored. Aggregates older than 365 days are purged. The pyhall.dev privacy policy applies.
Summary
Your system pyhall.dev registry────────────────────── ──────────────────────make_decision() ─── local only ───► (nothing)prefetch() ──────────────────────► GET verify/:worker_id (standing receipt)prefetch() ──────────────────────► POST telemetry/decisions (count only)startup ─── local only ────────► (nothing)