Pipecat's docs list every community-maintained plugin on one page: speech-to-text, text-to-speech, serializers, VAD, analytics, transports. Pick a vendor, pip install, follow the snippet.

For 19 of the 67 listed this morning, that doesn't work. The install fails, or the import raises, or the package pins a version of Pipecat from a year ago and quietly drags your whole environment backwards.

Nobody is hiding this. It's just that nothing was checking.

What the checker does

Every night, for each plugin on the supported-services page:

  1. Create a fresh environment.
  2. Install the plugin together with the latest pipecat-ai release on PyPI — what a new user gets today.
  3. Do it again against pipecat-ai main — what users get in the next release.
  4. Import the plugin and construct every Pipecat service class it defines.

No API keys are used anywhere, so this doesn't test whether a provider's servers answer. It tests the part that breaks far more often: install, import, and API shape — renamed or removed Pipecat symbols, new abstract methods, version pins.

The plugin list is re-read from the docs on every run, so new plugins are picked up automatically. That matters: the page had 56 entries three weeks ago and has 67 today.

Results from this morning's run, against pipecat-ai 1.12.0:

Status Count
Works 48
Partial 1
Broken on import 10
Pinned to an older Pipecat 5
Can't be installed at all 3

The failures cluster, and that's the interesting part

Six plugins die on the same line. In Pipecat 1.8 the settings sentinel _NotGiven was removed from pipecat.services.settings — it's NotGiven in pipecat.utils.types now. Six plugins still import the old name, so they raise before doing anything else:

ImportError: cannot import name '_NotGiven' from 'pipecat.services.settings' 

Six different companies, six separate repositories, one upstream rename. Each fix is a single import line.

Three more broke on renamed frames. One imports StartInterruptionFrame, another LLMMessagesFrame, another assert_given — none of which exist under those names any more.

Two are missing their own dependency. The plugin expects a vendor SDK that isn't installable from where it looks for it.

Five pin Pipecat backwards. One requires pipecat-ai>=0.0.97,<0.1.0. Another wants ==0.0.105. A third pins ==1.8.1 exactly. These don't error — which is worse. Your resolver silently downgrades Pipecat, or refuses to solve, and the reason isn't obvious from the traceback you eventually get.

Three can't be installed at all. Two checkouts have neither a pyproject.toml nor a setup.py, so there's nothing to install. One isn't on PyPI under the name the docs use.

This is not upstream's fault

It would be easy to read the _NotGiven cluster as Pipecat breaking its ecosystem. It isn't.

The 1.8.0 changelog flagged the change with a ⚠️ and spelled out the migration:

NOT_GIVEN, NotGiven, is_given() and assert_given() now come from pipecat.utils.types and are no longer importable from pipecat.services.settings. The private pipecat.services.settings._NotGiven is now the public pipecat.utils.types.NotGiven.

They announced it, named the destination, and were right that the old name was private — plugin authors were importing an underscore-prefixed symbol out of someone else's module, which was always going to be fragile.

The supported-services page is equally clear about ownership: community plugins are distributed separately and issues go to their own repositories.

So upstream did the things you'd ask for. The breakage happened anyway.

Why it keeps happening

Community plugins live in their own repositories, usually maintained by one engineer at the vendor. Pipecat ships often and moves fast, which is a virtue. But a plugin repo has no CI that installs against Pipecat main, so an upstream rename doesn't produce a red build anywhere — it produces a broken install six weeks later, for a user who has no relationship with either party and will simply choose a different vendor.

That's the gap: the breakage is public, deterministic and cheap to detect, and there was no place where anyone looked at all of them at once.

It measures recovery too

Between two runs in September, one plugin loosened its pin and moved from "needs older Pipecat" to "works". That's the part I didn't expect to enjoy: the table isn't a wall of shame, it's a live picture. Anything on it can move, and most of these are one line away from moving.

Running against main as well as the current release is deliberate, and it's the part I'd most like vendors to use. A plugin that breaks against main today has until the next Pipecat release to fix it, rather than finding out from an issue after the fact.

If you're choosing a plugin

  • Check the pin before you check the features. Four of the five pinned plugins will silently downgrade Pipecat in your environment rather than fail, and you'll debug it as something else entirely.
  • An import test is a five-second question. python -c "import pipecat_<name>" in a fresh environment tells you more than a README.
  • Check when the repo last moved. All ten broken plugins have been broken since late August. That's visible from the outside before you commit.

I've been sending the fixes

Rather than just publishing a list, I opened PRs for the ones I could fix from outside — eleven of them across eleven repositories.

What happened next is its own post, and it isn't the happy ending: three weeks on, none of them have merged. I'll write that one up separately, because the result surprised me more than the original findings did.

The repo, with the full table and the nightly results:
https://github.com/Rehansanjay/pipecat-plugin-health

If your plugin is on the broken list and you'd rather have a PR than a bug report, say so and I'll send one.