Source change
Upstream PR merged to MervinPraison/PraisonAI main on 2026-04-28:
Three architectural gaps were closed in the praisonai wrapper layer. Two of them produce user-visible behaviour that needs documentation, and one introduces a brand-new public extensibility API that has no documentation today. Another agent picking this up will create / update the pages described below.
TL;DR — recommended doc plan
| Action |
Page |
Folder |
Reason |
| CREATE |
framework-adapter-plugins.mdx |
docs/features/ |
New public API: third-party framework adapters via Python entry points (praisonai.framework_adapters group). No existing page covers it. docs/features/plugins.mdx only covers tool/hook/guardrail plugins. |
| UPDATE |
docs/cli/cli.mdx and docs/cli/cli-reference.mdx |
docs/cli/ |
Typer is now the single CLI dispatcher. The legacy argparse path is now a narrow shim for bare prompt or bare YAML only. Registration errors now fail loud instead of silently falling back. |
| UPDATE |
docs/features/thread-safety.mdx |
docs/features/ |
praisonai._async_bridge.run_sync() now raises RuntimeError when called from inside a running event loop — previously it auto-fell-back. This is a behaviour change worth a callout. Also note the new thread-safe lazy loaders in praisonai/auto.py and the loop-aware async primitives in async_agent_scheduler.py. |
| CROSS-LINK |
docs/framework/crewai.mdx, docs/framework/autogen.mdx, docs/framework/praisonaiagents.mdx |
docs/framework/ |
Add a “Custom frameworks” callout linking to the new framework-adapter-plugins.mdx page so readers learn the framework list is now extensible. |
Per AGENTS.md §1.8 — all new pages go in docs/features/, NEVER in docs/concepts/. Update docs.json under the Features group only.
Page 1 — NEW: docs/features/framework-adapter-plugins.mdx
Why this is needed
Before PR #1548, the available frameworks (crewai, autogen, autogen_v4, ag2, praisonai) were hardcoded in a FRAMEWORK_ADAPTERS dict inside agents_generator.py. After PR #1548, framework adapters live in a proper registry and third parties can register their own adapters via Python entry points. This is a new public extensibility surface.
SDK ground truth (read these before writing)
In the MervinPraison/PraisonAI repo (NOT in this docs repo):
src/praisonai/praisonai/framework_adapters/registry.py — new file, defines FrameworkAdapterRegistry
src/praisonai/praisonai/framework_adapters/base.py — defines the FrameworkAdapter Protocol
src/praisonai/praisonai/framework_adapters/crewai_adapter.py, autogen_adapter.py, praisonai_adapter.py — built-in adapters (read for shape of what users must implement)
src/praisonai/praisonai/agents_generator.py — now uses FrameworkAdapterRegistry.get_instance().create(framework) instead of the hardcoded dict
Key facts from the SDK (verify by reading source — do not paraphrase from this issue)
- Entry point group name:
praisonai.framework_adapters
- Singleton access:
FrameworkAdapterRegistry.get_instance()
- Public methods:
register(name, adapter_class), unregister(name), create(name), list_registered(), is_available(name)
- Built-in adapters auto-registered:
crewai, autogen, autogen_v4, ag2, praisonai (each guarded by lazy try/except ImportError so missing optional deps do not break the registry)
- Failure mode: if an entry-point plugin fails to load, the registry logs a warning and continues — it does not break framework dispatch
- Adapter contract:
FrameworkAdapter is a Protocol, so users implement it duck-typed. They must provide whatever the protocol requires (read base.py to enumerate methods — at minimum is_available() plus the methods called by agents_generator.py).
Required page sections (per AGENTS.md template)
- Frontmatter —
title: "Framework Adapter Plugins", icon: "puzzle-piece" (matches existing plugin docs)
- Hero Mermaid diagram — third-party package → entry point → registry → CLI
--framework <name> dispatch
- Quick Start (Steps component) with two steps:
- Step 1: programmatic registration via
FrameworkAdapterRegistry.get_instance().register("myframework", MyAdapter) — the simplest path
- Step 2: distribute as a pip-installable plugin via
pyproject.toml entry point under group praisonai.framework_adapters
- How It Works — sequence diagram:
pip install → entry-point discovery on first registry access → praisonai --framework myframework agents.yaml resolves through the registry
- Configuration / API table for the public
FrameworkAdapterRegistry methods listed above
- Common Patterns — at least: (a) overriding a built-in adapter, (b) wrapping a non-Python framework via subprocess, (c) availability check that returns
False when optional deps are missing
- Best Practices (AccordionGroup) — handle missing optional deps inside
is_available(); do not raise from import-time module code; log via logging.getLogger(__name__) not print
- Related (CardGroup, 2 cards) — link to
docs/features/plugins.mdx and docs/framework/crewai.mdx (or whichever framework page is most relevant as a “see how a built-in adapter looks” reference)
Example skeleton (snippets the next agent should adapt after reading the SDK — do not copy verbatim)
# pyproject.toml of the third-party package
[project.entry-points."praisonai.framework_adapters"]
myframework = "myframework_praisonai.adapter:MyFrameworkAdapter"
# Programmatic registration (alternative to entry points)
from praisonai.framework_adapters.registry import FrameworkAdapterRegistry
from myframework_praisonai.adapter import MyFrameworkAdapter
FrameworkAdapterRegistry.get_instance().register("myframework", MyFrameworkAdapter)
praisonai --framework myframework agents.yaml
docs.json change
Add the new page under the Features group only. Do NOT add it under Concepts.
Page 2 — UPDATE: docs/cli/cli.mdx and docs/cli/cli-reference.mdx
What changed
src/praisonai/praisonai/__main__.py was rewritten. The new dispatch rules are:
--version / -V → print version and exit
- Legacy shim — only triggers for:
- A first positional arg containing a space (free-text prompt), or
- A first positional arg ending in
.yaml/.yml that exists on disk
- Everything else → Typer
Notable user-visible consequences:
--help / -h is no longer special-cased — it goes through Typer (Typer already handles help correctly, so behaviour is the same, but the routing comment in any existing docs/diagrams should reflect this)
- A YAML path that does not exist on disk no longer falls into the legacy path — it goes to Typer, which will emit a clear unknown-command error instead of silently mis-dispatching
- Fail loud: if
register_commands() raises (e.g. a Typer subcommand has an ImportError), the CLI now propagates the exception instead of silently falling back to legacy dispatch. Users who previously saw mysterious legacy behaviour will now see the real error.
What the doc update should add
- A short "How CLI dispatch works" subsection (1 paragraph + a small Mermaid
graph TB showing the three routing rules)
- A
<Note> callout: "PraisonAI now fails loud on CLI registration errors. If you see a new ImportError after upgrading, a Typer subcommand or one of its dependencies failed to import — fix the import rather than ignoring the error."
- Verify any existing examples that pass a YAML path also note that the file must exist (no behavioural surprise, but worth being explicit)
Where NOT to change
Do not touch docs/concepts/* (per AGENTS.md §1.8). Stay in docs/cli/.
Page 3 — UPDATE: docs/features/thread-safety.mdx
What changed
-
praisonai._async_bridge.run_sync() is now strict about event loops. It used to detect a running loop and schedule the coroutine on the background loop in either case. It now raises RuntimeError if called from inside a running event loop, with the message:
run_sync() cannot be called from a running event loop; await the coroutine directly instead.
This is a behaviour change. Any user code that called run_sync() from an async context will now break loudly instead of silently working through a background-loop hop.
-
AsyncAgentScheduler is now loop-aware. start() binds its async primitives (asyncio.Event, asyncio.Lock) to the running loop, and stop() raises RuntimeError if called from a different loop than start().
-
praisonai/auto.py lazy loaders are now thread-safe. A single _load_optional(key, loader) helper with a module-level lock replaces the previous unguarded module-level globals (_crewai_available, _autogen_module, etc.).
-
praisonai/integrations/registry.py — the singleton registry now has a per-instance threading.Lock guarding register/unregister/create/list_registered and snapshots the dict before async iteration in get_available().
-
Telemetry init in praisonai/__init__.py now uses double-checked locking (already commented as such in the new code).
What the doc update should add
-
A new "Behaviour change in PR #1548" <Warning> callout near the top of the page explaining the run_sync() change with a before/after code example:
# Before PR #1548 (worked, but unsafe)
async def handler():
result = run_sync(some_coro()) # silently used background loop
# After PR #1548 (raises RuntimeError)
async def handler():
result = await some_coro() # use this from async context
-
A short note that the wrapper-layer lazy loaders, integration registry, and async scheduler primitives are now thread-safe and loop-aware (one paragraph each, no need to enumerate every file)
Cross-link updates (small)
In each of docs/framework/crewai.mdx, docs/framework/autogen.mdx, docs/framework/praisonaiagents.mdx, add a one-line callout near the top:
Need a framework that isn't listed here? See Framework Adapter Plugins to register your own via Python entry points.
Verification checklist for the implementing agent
Per AGENTS.md §1.1–§1.3 (SDK-first cycle):
Out of scope (do not document)
- Internal LRU cache details for OpenAI clients in
auto.py — implementation detail, not user-facing
- Internal
_load_optional helper — implementation detail
- The
get_unlocked() method on _BG — internal to _async_bridge.py
Source change
Upstream PR merged to
MervinPraison/PraisonAImainon 2026-04-28:7653e0342ee9328ffd53fb48e04e3d181bcf8768Three architectural gaps were closed in the
praisonaiwrapper layer. Two of them produce user-visible behaviour that needs documentation, and one introduces a brand-new public extensibility API that has no documentation today. Another agent picking this up will create / update the pages described below.TL;DR — recommended doc plan
framework-adapter-plugins.mdxdocs/features/praisonai.framework_adaptersgroup). No existing page covers it.docs/features/plugins.mdxonly covers tool/hook/guardrail plugins.docs/cli/cli.mdxanddocs/cli/cli-reference.mdxdocs/cli/docs/features/thread-safety.mdxdocs/features/praisonai._async_bridge.run_sync()now raisesRuntimeErrorwhen called from inside a running event loop — previously it auto-fell-back. This is a behaviour change worth a callout. Also note the new thread-safe lazy loaders inpraisonai/auto.pyand the loop-aware async primitives inasync_agent_scheduler.py.docs/framework/crewai.mdx,docs/framework/autogen.mdx,docs/framework/praisonaiagents.mdxdocs/framework/framework-adapter-plugins.mdxpage so readers learn the framework list is now extensible.Page 1 — NEW:
docs/features/framework-adapter-plugins.mdxWhy this is needed
Before PR #1548, the available frameworks (
crewai,autogen,autogen_v4,ag2,praisonai) were hardcoded in aFRAMEWORK_ADAPTERSdict insideagents_generator.py. After PR #1548, framework adapters live in a proper registry and third parties can register their own adapters via Python entry points. This is a new public extensibility surface.SDK ground truth (read these before writing)
In the
MervinPraison/PraisonAIrepo (NOT in this docs repo):src/praisonai/praisonai/framework_adapters/registry.py— new file, definesFrameworkAdapterRegistrysrc/praisonai/praisonai/framework_adapters/base.py— defines theFrameworkAdapterProtocolsrc/praisonai/praisonai/framework_adapters/crewai_adapter.py,autogen_adapter.py,praisonai_adapter.py— built-in adapters (read for shape of what users must implement)src/praisonai/praisonai/agents_generator.py— now usesFrameworkAdapterRegistry.get_instance().create(framework)instead of the hardcoded dictKey facts from the SDK (verify by reading source — do not paraphrase from this issue)
praisonai.framework_adaptersFrameworkAdapterRegistry.get_instance()register(name, adapter_class),unregister(name),create(name),list_registered(),is_available(name)crewai,autogen,autogen_v4,ag2,praisonai(each guarded by lazytry/except ImportErrorso missing optional deps do not break the registry)FrameworkAdapteris aProtocol, so users implement it duck-typed. They must provide whatever the protocol requires (readbase.pyto enumerate methods — at minimumis_available()plus the methods called byagents_generator.py).Required page sections (per AGENTS.md template)
title: "Framework Adapter Plugins",icon: "puzzle-piece"(matches existing plugin docs)--framework <name>dispatchFrameworkAdapterRegistry.get_instance().register("myframework", MyAdapter)— the simplest pathpyproject.tomlentry point under grouppraisonai.framework_adapterspip install→ entry-point discovery on first registry access →praisonai --framework myframework agents.yamlresolves through the registryFrameworkAdapterRegistrymethods listed aboveFalsewhen optional deps are missingis_available(); do not raise from import-time module code; log vialogging.getLogger(__name__)not printdocs/features/plugins.mdxanddocs/framework/crewai.mdx(or whichever framework page is most relevant as a “see how a built-in adapter looks” reference)Example skeleton (snippets the next agent should adapt after reading the SDK — do not copy verbatim)
docs.json change
Add the new page under the Features group only. Do NOT add it under Concepts.
Page 2 — UPDATE:
docs/cli/cli.mdxanddocs/cli/cli-reference.mdxWhat changed
src/praisonai/praisonai/__main__.pywas rewritten. The new dispatch rules are:--version/-V→ print version and exit.yaml/.ymlthat exists on diskNotable user-visible consequences:
--help/-his no longer special-cased — it goes through Typer (Typer already handles help correctly, so behaviour is the same, but the routing comment in any existing docs/diagrams should reflect this)register_commands()raises (e.g. a Typer subcommand has anImportError), the CLI now propagates the exception instead of silently falling back to legacy dispatch. Users who previously saw mysterious legacy behaviour will now see the real error.What the doc update should add
graph TBshowing the three routing rules)<Note>callout: "PraisonAI now fails loud on CLI registration errors. If you see a new ImportError after upgrading, a Typer subcommand or one of its dependencies failed to import — fix the import rather than ignoring the error."Where NOT to change
Do not touch
docs/concepts/*(per AGENTS.md §1.8). Stay indocs/cli/.Page 3 — UPDATE:
docs/features/thread-safety.mdxWhat changed
praisonai._async_bridge.run_sync()is now strict about event loops. It used to detect a running loop and schedule the coroutine on the background loop in either case. It now raisesRuntimeErrorif called from inside a running event loop, with the message:This is a behaviour change. Any user code that called
run_sync()from an async context will now break loudly instead of silently working through a background-loop hop.AsyncAgentScheduleris now loop-aware.start()binds its async primitives (asyncio.Event,asyncio.Lock) to the running loop, andstop()raisesRuntimeErrorif called from a different loop thanstart().praisonai/auto.pylazy loaders are now thread-safe. A single_load_optional(key, loader)helper with a module-level lock replaces the previous unguarded module-level globals (_crewai_available,_autogen_module, etc.).praisonai/integrations/registry.py— the singleton registry now has a per-instancethreading.Lockguardingregister/unregister/create/list_registeredand snapshots the dict before async iteration inget_available().Telemetry init in
praisonai/__init__.pynow uses double-checked locking (already commented as such in the new code).What the doc update should add
A new "Behaviour change in PR #1548"
<Warning>callout near the top of the page explaining therun_sync()change with a before/after code example:A short note that the wrapper-layer lazy loaders, integration registry, and async scheduler primitives are now thread-safe and loop-aware (one paragraph each, no need to enumerate every file)
Cross-link updates (small)
In each of
docs/framework/crewai.mdx,docs/framework/autogen.mdx,docs/framework/praisonaiagents.mdx, add a one-line callout near the top:Verification checklist for the implementing agent
Per
AGENTS.md§1.1–§1.3 (SDK-first cycle):src/praisonai/praisonai/framework_adapters/registry.pyfromMervinPraison/PraisonAImain(post-merge of #1548) — do not rely on the snippets in this issuesrc/praisonai/praisonai/framework_adapters/base.pyto enumerate the exactFrameworkAdapterprotocol methodscrewai_adapter.py) to show users a realistic shapesrc/praisonai/praisonai/__main__.py(post-merge) to confirm the exact dispatch rules before updating CLI docssrc/praisonai/praisonai/_async_bridge.py(post-merge) to confirm the exactRuntimeErrormessagedocs/features/onlydocs.jsonupdates go under the Features group only<Steps>,<AccordionGroup>,<CardGroup>,<Note>/<Warning>AGENTS.md§3.1your-key-hereplaceholders)Out of scope (do not document)
auto.py— implementation detail, not user-facing_load_optionalhelper — implementation detailget_unlocked()method on_BG— internal to_async_bridge.py