Quick Start
1. Install
pip install pyhall-wcpRequires Python 3.10+. No mandatory external dependencies beyond Pydantic v2.
npm install @pyhall/core @pyhall/cli2. Build a Worker Registry Record
The pyhall build command launches an interactive wizard that generates a registry record — the enrollment document a worker submits to the Hall. It declares capabilities, risk tier, controls, and blast radius.
pyhall buildThe wizard prompts for worker ID, capabilities, risk tier, controls, and privilege envelope, then writes the file. A generated registry_record.json will look like this:
{ "worker_id": "org.acme.summarizer", "worker_species_id": "wrk.doc.summarizer", "capabilities": ["cap.doc.summarize"], "risk_tier": "low", "idempotency": "full", "determinism": "captured", "required_controls": ["ctrl.obs.audit-log-append-only"], "currently_implements": ["ctrl.obs.audit-log-append-only"], "allowed_environments": ["dev", "stage", "prod"], "privilege_envelope": { "secrets_access": [], "network_egress": "none", "filesystem_writes": ["/tmp/summaries/"], "tools": [] }, "blast_radius": { "data": 1, "network": 0, "financial": 0, "time": 1, "reversibility": "reversible" }, "owner": "org.acme", "contact": "you@acme.com", "artifact_hash": "sha256:...", "catalog_version_min": "1.0.0"}3. Start the Hall API
python -m hall_api.serverThe Hall API starts on http://localhost:8765 by default. It loads routing rules from rules.json and enrolled workers from the enrolled/ directory in the current working directory.
Check it is running:
curl http://localhost:8765/health4. Enroll the Worker
curl -X POST http://localhost:8765/enroll \ -H "Content-Type: application/json" \ -d @my_summarizer/registry_record.jsonThe Hall verifies the artifact_hash on receipt. A mismatch means the registry record was modified after it was generated — enrollment is rejected.
Successful enrollment response:
{ "enrolled": true, "enrollment_id": "enr_7a3f9c2b", "worker_id": "org.acme.summarizer", "artifact_hash_verified": true, "enrolled_at": "2026-02-25T00:00:00Z"}5. Make a Routing Decision
Use make_decision() directly in Python or the pyhall route CLI. The Hall API server does not expose a /route HTTP endpoint — routing is done in-process via the SDK.
import uuidfrom pyhall import make_decision, RouteInput, Registry, load_rules
# Load routing rules and enrolled workersrules = load_rules("rules.json")registry = Registry(registry_dir="enrolled/")
# Build a capability requestinp = RouteInput( capability_id="cap.doc.summarize", env="dev", data_label="INTERNAL", tenant_risk="low", qos_class="P2", tenant_id="org.acme", correlation_id=str(uuid.uuid4()),)
# Ask the Halldecision = make_decision( inp=inp, rules=rules, registry_controls_present=registry.controls_present(), registry_worker_available=registry.worker_available,)
if decision.denied: print(f"Denied: {decision.deny_reason_if_denied}")else: print(f"Dispatch: {decision.selected_worker_species_id}") # -> wrk.doc.summarizerpyhall route \ --capability cap.doc.summarize \ --env dev \ --data-label INTERNAL \ --rules rules.json6. What You Get Back
Every routing decision — allowed or denied — returns a complete RouteDecision:
{ "decision_id": "550e8400-e29b-41d4-a716-446655440001", "timestamp": "2026-02-25T12:00:00Z", "correlation_id": "550e8400-e29b-41d4-a716-446655440000", "tenant_id": "org.acme", "capability_id": "cap.doc.summarize", "matched_rule_id": "rr_doc_summarize_dev", "selected_worker_species_id": "wrk.doc.summarizer", "env": "dev", "data_label": "INTERNAL", "tenant_risk": "low", "qos_class": "P2", "denied": false, "deny_reason_if_denied": null, "required_controls_effective": ["ctrl.obs.audit-log-append-only"], "escalation_effective": { "policy_gate": true, "human_required_default": false }, "artifact_hash": "sha256:7b3f9c2a...", "worker_attestation_checked": false, "dry_run": false, "telemetry_envelopes": [ {"event_id": "evt.os.task.routed", "timestamp": "2026-02-25T12:00:00Z", "correlation_id": "550e8400..."}, {"event_id": "evt.os.worker.selected","timestamp": "2026-02-25T12:00:00Z", "correlation_id": "550e8400..."}, {"event_id": "evt.os.policy.gated", "timestamp": "2026-02-25T12:00:00Z", "correlation_id": "550e8400..."} ]}The artifact_hash proves exactly what was routed. The telemetry_envelopes carry the three mandatory WCP events. The correlation_id propagates through all downstream worker calls.
Next Steps
- Workers — registry records, risk tiers, lifecycle
- Capabilities — capability IDs, namespaces, why you request by capability
- Policies & Risk — blast radius, policy profiles, controls
- Decisions & Routing — RouteInput, RouteDecision, deny codes