Runtimes & compatibility
Running pipedog on Bun, Node, Deno and Cloudflare Workers, and which packages are verified where.
@pipedog/core and @pipedog/asyncio are runtime-agnostic: they run unchanged on Bun,
Node.js (22 or later), Deno and Cloudflare Workers (workerd). Code that only works on
some runtimes lives in its own package, and every package records where it is verified.
Compatibility table
Generated at build time from the pipecat.runtimes field of each packages/*/package.json:
| Package | Bun | Node.js | Deno | Cloudflare Workers |
|---|---|---|---|---|
@pipedog/asyncio | ✅ | ✅ | ✅ | ✅ |
@pipedog/corepipecat/frames, pipecat/processors/frame_processor.py, pipecat/pipeline, pipecat/workers, pipecat/observers, pipecat/clocks, pipecat/utils | ✅ | ✅ | ✅ | ✅ |
@pipedog/ai-sdk | ✅ | ✅ | ✅ | ✅ |
@pipedog/anthropicpipecat/adapters/llm/services/anthropic_adapter.py, pipecat/services/anthropic | ✅ | ✅ | ✅ | ✅ |
@pipedog/assemblyaipipecat/services/assemblyai | ✅ | ✅ | ✅ | ✅ |
@pipedog/asyncaipipecat/services/asyncai | ✅ | ✅ | ✅ | ✅ |
@pipedog/audio-ducking | ✅ | ✅ | ✅ | ✅ |
@pipedog/audio-rnnoise-filterpipecat/audio/filters/rnnoise_filter.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/audio-sileropipecat/audio/vad/silero.py, pipecat/audio/vad/data/silero_vad.onnx | ✅ | ✅ | ✅ | ✅ |
@pipedog/audio-smart-turnpipecat/audio/turn/smart_turn/http_smart_turn.py, pipecat/audio/turn/smart_turn/data/smart-turn-v3.2-cpu.onnx | ✅ | ✅ | ✅ | ✅ |
@pipedog/audio-soundfile-mixerpipecat/audio/mixers/soundfile_mixer.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/audio-ten-vad | ✅ | ✅ | — | ✅ |
@pipedog/awspipecat/adapters/llm/services/aws_nova_sonic_adapter.py, pipecat/adapters/llm/services/bedrock_adapter.py, pipecat/services/aws | ✅ | ✅ | ✅ | ✅ |
@pipedog/azurepipecat/services/azure, pipecat/adapters/llm/services/azure_voice_live_adapter.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/basetenpipecat/services/baseten | ✅ | ✅ | ✅ | ✅ |
@pipedog/blandpipecat/services/bland | ✅ | ✅ | ✅ | ✅ |
@pipedog/cambpipecat/services/camb | ✅ | ✅ | ✅ | ✅ |
@pipedog/cartesiapipecat/services/cartesia | ✅ | ✅ | ✅ | ✅ |
@pipedog/cerebraspipecat/services/cerebras | ✅ | ✅ | ✅ | ✅ |
@pipedog/clipipecat/cli | ✅ | ✅ | ✅ | n/a |
@pipedog/cloudflare | ✅ | ✅ | ✅ | ✅ |
@pipedog/crusoepipecat/services/crusoe | ✅ | ✅ | ✅ | ✅ |
@pipedog/deepgrampipecat/services/deepgram | ✅ | ✅ | ✅ | ✅ |
@pipedog/deepseekpipecat/adapters/llm/services/deepseek_adapter.py, pipecat/services/deepseek | ✅ | ✅ | ✅ | ✅ |
@pipedog/effect | ✅ | ✅ | ✅ | ✅ |
@pipedog/elevenlabspipecat/services/elevenlabs | ✅ | ✅ | ✅ | ✅ |
@pipedog/espeak-ng | ✅ | ✅ | ✅ | n/a |
@pipedog/evalspipecat/evals, pipecat/cli/commands/eval.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/extensionspipecat/extensions | ✅ | ✅ | ✅ | ✅ |
@pipedog/fireworkspipecat/services/fireworks | ✅ | ✅ | ✅ | ✅ |
@pipedog/fishpipecat/services/fish | ✅ | ✅ | ✅ | ✅ |
@pipedog/flowspipecat/flows | ✅ | ✅ | ✅ | ✅ |
@pipedog/funasrpipecat/services/funasr/stt.py | ✅ | ✅ | ✅ | n/a |
@pipedog/gladiapipecat/services/gladia | ✅ | ✅ | ✅ | ✅ |
@pipedog/googlepipecat/services/google | ✅ | ✅ | ✅ | ✅ |
@pipedog/gradiumpipecat/services/gradium | ✅ | ✅ | ✅ | ✅ |
@pipedog/grokpipecat/services/grok/llm.py, pipecat/services/grok/realtime, pipecat/adapters/llm/services/grok_realtime_adapter.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/groqpipecat/services/groq | ✅ | ✅ | ✅ | ✅ |
@pipedog/heygenpipecat/services/heygen | ✅ | ✅ | ✅ | n/a |
@pipedog/humepipecat/services/hume | ✅ | ✅ | ✅ | ✅ |
@pipedog/inceptionpipecat/services/inception | ✅ | ✅ | ✅ | ✅ |
@pipedog/inworldpipecat/services/inworld, pipecat/adapters/llm/services/inworld_realtime_adapter.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/kokoropipecat/services/kokoro/tts.py | ✅ | ✅ | ✅ | n/a |
@pipedog/langchainpipecat/processors/frameworks/langchain.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/mcp | ✅ | ✅ | n/a | n/a |
@pipedog/mcp-clientpipecat/services/mcp_service.py | ✅ | ✅ | ✅ | ⚠️ |
@pipedog/metapipecat/services/meta | ✅ | ✅ | ✅ | ✅ |
@pipedog/minimaxpipecat/services/minimax | ✅ | ✅ | ✅ | ✅ |
@pipedog/mistralpipecat/adapters/llm/services/mistral_adapter.py, pipecat/services/mistral | ✅ | ✅ | ✅ | ✅ |
@pipedog/moonshinepipecat/services/moonshine/stt.py | ✅ | ✅ | ✅ | n/a |
@pipedog/nebiuspipecat/services/nebius | ✅ | ✅ | ✅ | ✅ |
@pipedog/neuphonicpipecat/services/neuphonic | ✅ | ✅ | ✅ | ✅ |
@pipedog/novitapipecat/services/novita | ✅ | ✅ | ✅ | ✅ |
@pipedog/nvidiapipecat/adapters/llm/services/nvidia_omni_adapter.py, pipecat/services/nvidia | ✅ | ✅ | — | ✅ |
@pipedog/ollamapipecat/services/ollama | ✅ | ✅ | ✅ | ✅ |
@pipedog/onnx | ✅ | ✅ | ✅ | ✅ |
@pipedog/openaipipecat/services/openai, pipecat/adapters/llm/services/open_ai_live_adapter.py, pipecat/adapters/llm/services/open_ai_realtime_adapter.py, pipecat/adapters/llm/services/open_ai_responses_adapter.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/openrouterpipecat/services/openrouter | ✅ | ✅ | ✅ | ✅ |
@pipedog/perplexitypipecat/adapters/llm/services/perplexity_adapter.py, pipecat/services/perplexity | ✅ | ✅ | ✅ | ✅ |
@pipedog/piperpipecat/services/piper/tts.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/pocket-ttspipecat/services/pocket_tts/tts.py | ✅ | ✅ | ✅ | n/a |
@pipedog/qwenpipecat/services/qwen | ✅ | ✅ | ✅ | ✅ |
@pipedog/resampler-wasm | ✅ | ✅ | ✅ | ✅ |
@pipedog/resembleaipipecat/services/resembleai | ✅ | ✅ | ✅ | ✅ |
@pipedog/rimepipecat/services/rime | ✅ | ✅ | ✅ | ✅ |
@pipedog/runnerpipecat/runner/__init__.py, pipecat/runner/livekit.py, pipecat/runner/run.py, pipecat/runner/types.py, pipecat/runner/utils.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/sambanovapipecat/services/sambanova | ✅ | ✅ | ✅ | ✅ |
@pipedog/sarvampipecat/services/sarvam | ✅ | ✅ | ✅ | ✅ |
@pipedog/sentencex-wasm | ✅ | ✅ | ✅ | ✅ |
@pipedog/sentrypipecat/processors/metrics/sentry.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/serializer-exotelpipecat/serializers/exotel.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/serializer-genesyspipecat/serializers/genesys.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/serializer-plivopipecat/serializers/plivo.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/serializer-protobufpipecat/serializers/protobuf.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/serializer-rtvi-clientpipecat/serializers/rtvi_client.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/serializer-telnyxpipecat/serializers/telnyx.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/serializer-twiliopipecat/serializers/twilio.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/serializer-vonagepipecat/serializers/vonage.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/smallestpipecat/services/smallest | ✅ | ✅ | ✅ | ✅ |
@pipedog/sonioxpipecat/services/soniox | ✅ | ✅ | ✅ | ✅ |
@pipedog/speechifypipecat/services/speechify | ✅ | ✅ | ✅ | ✅ |
@pipedog/speechmaticspipecat/services/speechmatics | ✅ | ✅ | ✅ | ✅ |
@pipedog/togetherpipecat/services/together | ✅ | ✅ | ✅ | ✅ |
@pipedog/tonepipecat/processors/tone/reader/model.py, pipecat/processors/tone/tagger/model.py | ✅ | ✅ | — | ✅ |
@pipedog/tracingpipecat/utils/tracing/setup.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/transport-cloudflare-realtime | ✅ | ✅ | ✅ | ✅ |
@pipedog/transport-heygenpipecat/transports/heygen/transport.py | ✅ | ✅ | ✅ | n/a |
@pipedog/transport-livekitpipecat/transports/livekit/transport.py, pipecat/transports/livekit/utils.py | ✅ | ✅ | ✅ | n/a |
@pipedog/transport-localpipecat/transports/local/audio.py | ✅ | ✅ | ✅ | n/a |
@pipedog/transport-smallwebrtcpipecat/transports/smallwebrtc/connection.py, pipecat/transports/smallwebrtc/request_handler.py, pipecat/transports/smallwebrtc/transport.py | ✅ | ✅ | ✅ | n/a |
@pipedog/transport-websocketpipecat/transports/websocket/client.py, pipecat/transports/websocket/fastapi.py, pipecat/transports/websocket/rtvi_client.py, pipecat/transports/websocket/server.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/transport-whatsapppipecat/transports/whatsapp/api.py, pipecat/transports/whatsapp/client.py | ✅ | ✅ | ✅ | ⚠️ |
@pipedog/ultravoxpipecat/services/ultravox | ✅ | ✅ | ✅ | ✅ |
@pipedog/whisperpipecat/services/whisper/base_stt.py, pipecat/services/whisper/stt.py, pipecat/services/whisper/utils.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/xaipipecat/services/xai/llm.py, pipecat/services/xai/stt.py, pipecat/services/xai/tts.py, pipecat/services/xai/realtime, pipecat/adapters/llm/services/grok_realtime_adapter.py | ✅ | ✅ | ✅ | ✅ |
@pipedog/zoom-aipipecat/services/zoom_ai | ✅ | ✅ | — | ✅ |
✅ = a smoke test exercises the package on that runtime (pipecat.runtimes in its package.json). ⚠️ = only part of it works there. n/a = the runtime can't run it. — = not verified yet. Generated at build time from 96 packages.
runtimes lists only what is verified: the compat harness runs each package's smoke test (its
compat/smoke.ts, or a default that imports every public entry) on each runtime, and
bun run compat --write records the runtimes that passed. It is never edited by hand. An empty
row means the package has not been run through the harness yet.
A package that cannot work on a runtime (SmallWebRTC on Workers, which has no UDP) lists it in
pipecat.compat.unsupportedRuntimes; the harness skips it there. Optional peers a package's users
are expected to install go in pipecat.compat.usesOptionalPeers; all other optional peers are made
unresolvable during the run, so a package that silently depends on one fails.
Every package is verified on all four runtimes except @pipedog/transport-smallwebrtc (no UDP
on Workers), @pipedog/transport-livekit, @pipedog/heygen and @pipedog/transport-heygen
(LiveKit's media SDK is a native addon, which Workers can't load), the local models
@pipedog/kokoro, @pipedog/moonshine, @pipedog/funasr, @pipedog/pocket-tts and the eSpeak NG
phonemizer @pipedog/espeak-ng (model files and memory exceed what Workers allow), @pipedog/transport-local
(it runs sox or ffmpeg on your machine), @pipedog/mcp (a stdio tool for Bun and Node) and @pipedog/cli (a command line tool: Bun, Node and Deno). The harness checks that each
package loads and runs its smoke test; inside a verified package, a few entry points still need a
server runtime:
| Entry point | Runs on | Why |
|---|---|---|
Google Cloud Speech-to-Text and Text-to-Speech, and Gemini TTS on GCP (@pipedog/google) | Bun, Node, Deno | gRPC over HTTP/2 through Google's Node SDKs. The Gemini API services run on Workers too. |
SageMakerBidiClient (@pipedog/aws) | Bun, Node 22+ (Deno untested) | Full-duplex HTTP/2 through the AWS SDK. |
Nova Sonic with transport: "http2" (@pipedog/aws) | Bun, Node (Deno untested) | The default WebSocket transport runs everywhere, Workers included. |
main(), serve() (@pipedog/runner) | Bun, Node (with ws), Deno | They listen on a port. On Workers, use the fetch handler from createRunnerApp() (untested there). |
serveFetch, websocketServe, SingleClientWebsocketServerTransport (@pipedog/transport-websocket) | Bun, Node (with ws), Deno | They listen on a port. On Workers, use websocketFetchHandler. |
Local turn detection (@pipedog/audio-silero, @pipedog/audio-smart-turn) runs on Workers with
onnxruntime-web, but the models and runtime are large; provider-side turn detection is the usual
choice there. See Turn detection.
What core avoids
To stay portable, @pipedog/core and @pipedog/asyncio:
- import no
node:*modules exceptnode:async_hooks(forAsyncLocalStorage, in asyncio); - use
Uint8Arrayfor bytes, neverBuffer(PCM is 16-bit little-endian); - use no Bun- or Deno-specific APIs;
- use the global
fetchandWebSocketfor network I/O; - treat process signals as optional (
WorkerRunnerhandles SIGINT/SIGTERM only where the runtime has them).
Bun, Node and Deno
The npm packages ship compiled JavaScript, and from a checkout Bun and Deno run the TypeScript
sources directly (Node with its built-in type stripping). WorkerRunner installs a SIGINT handler
by default, so Ctrl-C cancels the bot cleanly. Node needs version 22 or later.
On Bun and Node, a WebSocket is upgraded by the server rather than from the Request:
serveFetch() from @pipedog/transport-websocket/serve serves a fetch handler with upgrades on
Bun, Node (with the ws package) and Deno, and on Bun you can also pass the server Bun.serve
gives fetch to websocketFetchHandler's handler. See WebSocket.
Cloudflare Workers
Workers are a good fit for pipedog bots that talk to clients over WebSockets, with a few constraints:
-
Enable
nodejs_compat. Task tracking usesAsyncLocalStoragefromnode:async_hooks, which workerd provides under thenodejs_compatcompatibility flag.wrangler.jsonc { "compatibility_flags": ["nodejs_compat"] } -
No WebRTC. Workers can't run WebRTC, so the WebRTC-based transports (Daily, SmallWebRTC, LiveKit) don't work there. Use a WebSocket transport instead; WebSocket-based transports and serializers must work on Workers. Pipecat clients can connect over WebSocket with RTVI as usual. For WebRTC users, Cloudflare Realtime is the WebRTC peer and streams the audio to the bot over WebSockets.
-
WASM is imported as a module. workerd refuses to compile WebAssembly from bytes at runtime (
WebAssembly.compile(buffer)), so a.wasmfile must be imported. Packages with WASM ship two entries selected by theworkerdexport condition, which wrangler resolves automatically:package.json { "exports": { ".": { "types": "./src/index.ts", "workerd": "./src/workerd.ts", "default": "./src/index.ts" } } }The
workerdentry doesimport wasm from "../wasm/x.wasm"and instantiates thatWebAssembly.Module; the default entry loads the bytes (afetchofnew URL(..., import.meta.url)). Both accept an explicitWebAssembly.Module | BufferSourceso apps can supply their own.@pipedog/resampler-wasmis built this way. -
Models are never bundled. Packages that need a model (Silero VAD, Smart Turn) load it from a path or URL you give them, with the upstream file name as the default. On Workers, serve it from R2, KV, static assets or a
fetch. -
No threads, limited CPU. Upstream work done in a thread pool (
run_in_executor) runs inline or in an injected runner. Keep per-call CPU low: Workers have CPU-time limits. -
No process signals.
handleSigintis a no-op; end the runner from your Worker code (for example when the WebSocket closes) withrunner.end()orrunner.cancel(). -
Many sessions per isolate. One isolate serves many requests and Durable Objects.
@pipedog/asyncioruns each callback in the I/O context that scheduled it, so parallel sessions in separate Durable Objects don't do each other's I/O.examples/workers-durable-voice-agenttests this with parallel sessions on workerd.
Native and ML dependencies
Where Pipecat uses native modules (onnxruntime, Krisp, Koala, soxr), the pipedog package takes
the model as an external file or URL and accepts an injected runtime: onnxruntime-node on
Bun/Node, onnxruntime-web (WASM) on Workers. Pure-algorithm fallbacks, such as a linear
resampler, may live in core.
pipedog is an unofficial community TypeScript port of Pipecat. It is not affiliated with or endorsed by Daily or the Pipecat project.
Portions adapted from the Pipecat documentation, Copyright (c) 2024–2025 Daily, BSD-2-Clause (see apps/docs/LICENSE-pipecat-docs).