openai, docker, or aws has no effect — the built-in resolves. Runtime register(...) is the only deliberate override path.
pyproject.toml; overriding a built-in is always a deliberate, in-process decision.
Quick Start
1
Pick a name that does not collide
Names are matched case-insensitively against the built-ins of the registry you target.
openai, OpenAI, and OPENAI are the same key — pick something novel.2
Override a built-in deliberately (runtime only)
The one supported way to replace a built-in is an in-process
register(...) call:3
Confirm what resolved
Turn on
DEBUG logging to see the collision line noting that a shipped built-in kept its name.How It Works
Since PraisonAI PR #4176 the guard lives in the basePluginRegistry, so every registry that subclasses it inherits the behaviour. It is enforced once, not re-asserted per registry.
Some registries also honour deprecated (legacy) entry-point group spellings for backward compatibility. Legacy discovery runs first (so the canonical spelling wins on a clash), and since PraisonAI PR #4185 it applies the same built-in check — you cannot resurrect the old shadowing behaviour by falling back to a deprecated group.
Standalone installs of praisonai-sandbox and praisonai-deploy carry a vendored fallback copy of PluginRegistry that runs when praisonai-code isn’t importable (pip install praisonai-sandbox on its own). Since PraisonAI PR #4184 both vendored copies enforce the same built-in check — an entry point whose name (case-insensitive) matches a built-in is skipped on that path too, so the guarantee holds in every install shape. Prior to PR #4184 a standalone praisonai-sandbox install still let a pip plugin replace docker, and praisonai-deploy let one replace aws.
The same rule runs on the vendored fallback path used by standalone praisonai-sandbox / praisonai-deploy installs:
The log level is
DEBUG, not WARNING. Packages that legitimately re-declare their own built-ins as entry points (for external discoverability) do not spam users’ console output.Every Registry Is Guarded
The two groups that matter most decide where user code executes:praisonai.sandbox and praisonai.managed_backends. A pip-installed package cannot silently take over docker — whether via the canonical base class (PR #4176), the legacy group spelling (PR #4185), or the vendored fallback copy that runs when praisonai-sandbox / praisonai-deploy is installed standalone (PR #4184).
Since PR #4800, the local routes
ollama, ollama_chat, lm_studio, vllm, hosted_vllm are guarded built-ins under praisonai.llm_providers. A pip package publishing an entry point named ollama (or any of the five) is now silently skipped (DEBUG log) instead of taking over — matching the existing behaviour for openai. Plugin authors must use runtime register(..., override=True) to replace any of these.Accessor names differ per registry — read the source (or the per-registry page below) before wiring a runtime override. Several registries expose
get_default_registry() from their own module.Registries that honour a deprecated/legacy group spelling enforce the guard on that path too. Today the only one is
EndpointProviderRegistry (canonical praisonai.endpoint_providers, legacy praisonai.endpoints.providers, built-in mcp). A pip package publishing mcp under the deprecated group can no longer replace the built-in mcp endpoint provider.Standalone installs of
praisonai-sandbox and praisonai-deploy use a vendored fallback copy of PluginRegistry (they don’t import praisonai-code). Since PR #4184 those fallback copies enforce the same built-in check — a pip package publishing docker (sandbox) or aws (deploy) on its own can no longer replace the built-in on those slim installs. Runtime register(...) on the standalone package’s registry remains the only supported override.Compatibility
Best Practices
Namespace your plugin names
Namespace your plugin names
Prefix or vendor-qualify a plugin name (
acme-openai, corp.pay_invoice) so it never collides with a built-in on any surface, present or future.Reserve register(...) for deliberate overrides
Reserve register(...) for deliberate overrides
A runtime
register(...) call is in-process and explicit — exactly what you want when overriding a built-in is intentional (a tenant-specific provider, a test double). It cannot happen by accident through packaging.Check collisions case-insensitively
Check collisions case-insensitively
OpenAI, openai, and OPENAI are one key. When you audit a registry’s built-ins before naming a plugin, lowercase both sides.Debug with DEBUG logging
Debug with DEBUG logging
A skipped collision writes a
DEBUG line, not a warning. Run with LOGLEVEL=DEBUG to confirm which built-in kept its name.Related
Integration Registry
praisonai.integrations entry points and built-in precedenceExternal CLI Integrations
claude, gemini, codex, cursor are protected namesTool Source Registry
Built-in tool sources win over entry-point sources
Tool Discovery Order
Where the plugin layer sits, and why built-ins outrank it
Compute Provider Plugins
Sandbox / managed-backend names decide where code runs
Custom LLM Provider
Override
openai / anthropic / google at runtimePlugins
Write, load, and ship plugins as pip packages
Pure Mode
Skip entry-point discovery for a single run

