shouldertap package. It offers two integration styles: an HTTP client for a consumer running as its own service, and in-process registration for a consumer embedded in the same process as the engine.
ShoulderTapClient
ShoulderTapClient is a thin HTTP client over the Protocol API. Import it and the contracts you’ll pass:
Methods
ShoulderTapClient(base_url='http://localhost:8776/api/v1', *, api_token=None)
Construct a client.
api_token is sent as Authorization: Bearer <token> on every request. Supports use as a context manager (with ShoulderTapClient(...) as client:), which closes the underlying HTTP connection on exit.ask(request: ContextRequest) -> dict
Submit a request (
POST /requests). Returns { id, status }.get_request(request_id: str) -> dict
Fetch a request’s current status and, once resolved, its accepted proposal (
GET /requests/{id}).register(registration: ConsumerRegistration) -> dict
Register a consumer (
POST /consumers).unregister(consumer_id: str) -> None
Remove a consumer (
DELETE /consumers/{id}).close() -> None
Close the HTTP connection. Called automatically when used as a context manager.
In-process consumers
If your consumer runs in the same process as the engine, you can skip HTTP and webhooks entirely and receive answers as direct callbacks. Register withregister_in_process:
on_proposal, on_proposal_accepted, on_proposal_rejected(proposal, reason), and on_request_failed(request_id, reason) — but as in-process method calls with no serialization or network hop.
register_in_process takes a ConsumerDeliverer from shouldertap.engine.delivery, which the engine provides when your consumer is wired into it. Use this style when you’re embedding ShoulderTap as a library; use ShoulderTapClient plus webhooks when your consumer is a separate service.