Skip to main content
Patchwork publishes run events to a private channel per thread over Pusher. We own the Pusher account — your client fetches public config from us and asks us to sign its subscription. This is the only transport that carries every event type, including the streaming deltas and render blocks that no other transport can use. Everything else, including the pause events that tell you a run needs a human, is also deliverable by webhook.

Connecting

1

Fetch config

GET /v1/loom/realtime/config returns { enabled, key, cluster }. If enabled is false, realtime is not configured for this workspace — fall back to polling.
2

Subscribe

The channel is private-thread- plus the thread UUID.
3

Authorize

Your client’s subscription request goes to POST /v1/loom/realtime/auth with channel_name and socket_id. We check the caller owns that thread and return the Pusher auth payload.
A subject can only subscribe to its own threads. Asking to sign a channel for someone else’s thread returns 403.

The React SDK does this for you

@usepatchwork/react fetches config, subscribes, authorizes, and falls back to polling when realtime is disabled. If your agent lives in a React app, start there rather than wiring Pusher by hand.

Falling back

Realtime is an optimisation, not a requirement. Everything it tells you is also discoverable: The one thing polling cannot reproduce is message.delta — streaming fragments only exist on the wire.

Choosing a transport

  • A chat UI — realtime. Streaming is most of the experience.
  • A backend integration — webhooks for terminal events, polling for pauses.
  • A batch job — polling. There is no session to stream to.