Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.praison.ai/llms.txt

Use this file to discover all available pages before exploring further.

Plugins let you add logging, metrics, tools, and custom behavior to your agents. Create plugins as simple Python files - no classes needed.

Quick Start

Create a plugin file and place it in the plugins directory:
1

Create Plugin File

Create ~/.praisonai/plugins/my_tools.py:
"""
Plugin Name: My Tools
Description: Custom tools for my agent
Version: 1.0.0
"""

from praisonaiagents import tool

@tool
def get_weather(city: str) -> str:
    """Get weather for a city."""
    return f"☀️ Sunny in {city}, 72°F"
2

Use It

from praisonaiagents import Agent, discover_and_load_plugins

# Load plugins (registers tools to global registry)
discover_and_load_plugins()

# Reference tools by name
agent = Agent(
    name="Assistant",
    instructions="Help users",
    tools=["get_weather"]  # Tool name from plugin
)
agent.start("What's the weather in Paris?")
Plugin Location: Place plugins in ~/.praisonai/plugins/ (user-wide) or ./.praisonai/plugins/ (project-specific).

Plugin Locations

LocationScope
~/.praisonai/plugins/User-wide (all projects)
./.praisonai/plugins/Project-specific
# Create plugin directory
mkdir -p ~/.praisonai/plugins/

Tool Plugins

Provide additional tools that agents can use. Create ~/.praisonai/plugins/weather_tools.py:
"""
Plugin Name: Weather Tools
Description: Get weather for any city
Version: 1.0.0
"""

from praisonaiagents import tool

@tool
def get_weather(city: str) -> str:
    """Get current weather for a city."""
    return f"☀️ Sunny in {city}, 72°F"

@tool
def get_forecast(city: str, days: int = 5) -> str:
    """Get weather forecast for a city."""
    return f"📅 {days}-day forecast for {city}: Mostly sunny"
Use it:
from praisonaiagents import Agent, discover_and_load_plugins

# Load plugins (registers tools to global registry)
discover_and_load_plugins()

agent = Agent(
    name="Assistant",
    instructions="Help with weather",
    tools=["get_weather", "get_forecast"]  # Reference by name
)
agent.start("What's the weather in Tokyo?")

Hook Plugins

Intercept lifecycle events like tool calls, LLM requests, and agent start/end. Create ~/.praisonai/plugins/my_logger.py:
"""
Plugin Name: My Logger
Description: Logs all tool calls
Version: 1.0.0
Hooks: before_tool, after_tool
"""

from praisonaiagents.hooks import add_hook

@add_hook('before_tool')
def log_before(data):
    print(f"🔧 Calling: {data.tool_name}")

@add_hook('after_tool')
def log_after(data):
    print(f"✅ Result: {str(data.result)[:50]}")
Use it:
from praisonaiagents import Agent, discover_and_load_plugins

# Load plugins (registers hooks)
discover_and_load_plugins()

agent = Agent(name="Assistant", instructions="Help users")
agent.start("Search for Python tutorials")
# Hooks automatically log tool calls

Available Hooks

HookWhen CalledCan Modify
before_agentAgent startsPrompt
after_agentAgent finishesResponse
before_toolTool about to runArguments
after_toolTool finishedResult
before_llmLLM call startingMessages
after_llmLLM respondedResponse

Guardrail Plugins

Validate agent outputs before they’re returned. Create ~/.praisonai/plugins/safety_guardrail.py:
"""
Plugin Name: Safety Guardrail
Description: Blocks sensitive content
Version: 1.0.0
Hooks: after_agent
"""

from praisonaiagents.hooks import add_hook

BLOCKED_WORDS = ["password", "secret", "api_key", "token"]

@add_hook('after_agent')
def check_safety(data):
    response = str(data.result).lower()
    for word in BLOCKED_WORDS:
        if word in response:
            data.result = "[BLOCKED: Contains sensitive information]"
    return data
Use it:
from praisonaiagents import Agent, discover_and_load_plugins

# Load plugins (registers guardrails)
discover_and_load_plugins()

agent = Agent(name="Assistant", instructions="Help users")
agent.start("Show me the password")
# Output: [BLOCKED: Contains sensitive information]

LLM Plugins

Intercept and modify LLM calls for logging or token management. Create ~/.praisonai/plugins/token_counter.py:
"""
Plugin Name: Token Counter
Description: Counts tokens used in LLM calls
Version: 1.0.0
Hooks: after_llm
"""

from praisonaiagents.hooks import add_hook

total_tokens = 0

@add_hook('after_llm')
def count_tokens(data):
    global total_tokens
    usage = data.usage or {}
    total_tokens += usage.get("total_tokens", 0)
    print(f"📊 Total tokens: {total_tokens}")
Use it:
from praisonaiagents import Agent, discover_and_load_plugins

# Load plugins (registers LLM hooks)
discover_and_load_plugins()

agent = Agent(name="Assistant", instructions="Help users")
agent.start("Tell me a joke")
# Prints: 📊 Total tokens: 150

Plugin File Format

Every plugin file needs a header with metadata:
"""
Plugin Name: My Plugin Name
Description: What the plugin does
Version: 1.0.0
Author: Your Name (optional)
Hooks: before_tool, after_tool (optional, for hook plugins)
"""
FieldRequiredDescription
Plugin NameName of the plugin
DescriptionWhat the plugin does
VersionSemantic version
AuthorPlugin author
HooksHooks this plugin uses

CLI Commands

# Create a new plugin from template
praisonai plugins init my_plugin

# List all discovered plugins
praisonai plugins list

# Scan for plugins
praisonai plugins scan --verbose

Built-in Plugins

Enable built-in plugins without creating files:
from praisonaiagents import Agent, plugins

# Enable logging and metrics
plugins.enable(["logging", "metrics"])

agent = Agent(name="Assistant", instructions="Help users")
agent.start("What's the weather?")
---

## Lifecycle Hooks

Plugins intercept events at specific points in the agent lifecycle:


```mermaid
flowchart TB
    subgraph " "
        direction TB
        INPUT["📥 User Input"]
        
        subgraph AGENT_START["Agent Start"]
            BA["🪝 before_agent"]
        end
        
        subgraph TOOL_CYCLE["Tool Cycle (may repeat)"]
            BT["🪝 before_tool"]
            TOOL["🔧 Tool Executes"]
            AT["🪝 after_tool"]
        end
        
        subgraph LLM_CYCLE["LLM Call"]
            BL["🪝 before_llm"]
            LLM["🧠 LLM Generates"]
            AL["🪝 after_llm"]
        end
        
        subgraph AGENT_END["Agent Complete"]
            AA["🪝 after_agent"]
        end
        
        OUTPUT["📤 Response"]
    end
    
    INPUT --> BA
    BA --> BT
    BT --> TOOL
    TOOL --> AT
    AT --> BL
    BL --> LLM
    LLM --> AL
    AL --> AA
    AA --> OUTPUT
    
    style INPUT fill:#8B0000,color:#fff
    style OUTPUT fill:#8B0000,color:#fff
    style TOOL fill:#189AB4,color:#fff
    style LLM fill:#189AB4,color:#fff
    style BA fill:#6366F1,color:#fff
    style AA fill:#6366F1,color:#fff
    style BT fill:#10B981,color:#fff
    style AT fill:#10B981,color:#fff
    style BL fill:#F59E0B,color:#fff
    style AL fill:#F59E0B,color:#fff
HookStageCan Modify
before_agentAgent startsPrompt, context
before_toolTool about to runTool arguments
after_toolTool finishedTool result
before_llmLLM call startingMessages, params
after_llmLLM respondedLLM response
after_agentAgent finishingFinal response

Protocols

Type-safe plugin interfaces using Python protocols.
ProtocolPurposeKey Methods
PluginProtocolBase pluginname, version, on_init, on_shutdown
ToolPluginProtocolProvides toolsget_tools()
HookPluginProtocolIntercepts eventsbefore_tool, after_tool, etc.
AgentPluginProtocolAgent lifecyclebefore_agent, after_agent
LLMPluginProtocolLLM callsbefore_llm, after_llm
from praisonaiagents import (
    PluginProtocol,
    ToolPluginProtocol,
    HookPluginProtocol,
    AgentPluginProtocol,
    LLMPluginProtocol
)

# Check if object implements protocol
if isinstance(my_plugin, PluginProtocol):
    print("Valid plugin!")

# Implement specific protocol
class MyToolPlugin:
    @property
    def name(self) -> str:
        return "tool_provider"
    
    @property
    def version(self) -> str:
        return "1.0.0"
    
    def on_init(self, context):
        pass
    
    def on_shutdown(self):
        pass
    
    def get_tools(self):
        return [{"name": "my_tool", "description": "Does something"}]

# Type checker validates implementation
assert isinstance(MyToolPlugin(), ToolPluginProtocol)

Available Hooks

Core Hooks

HookWhen CalledCan Modify
ON_INITPlugin initializationContext
ON_SHUTDOWNPlugin shutdown-
BEFORE_AGENTBefore agent executionPrompt
AFTER_AGENTAfter agent executionResponse
BEFORE_TOOLBefore tool callArguments
AFTER_TOOLAfter tool callResult
BEFORE_LLMBefore LLM callMessages, Params
AFTER_LLMAfter LLM responseResponse
ON_PERMISSION_ASKPermission requestedApproval
ON_CONFIGConfiguration loadedConfig
ON_AUTHAuthentication neededCredentials

Extended Hooks

HookWhen CalledCan Modify
USER_PROMPT_SUBMITUser submits promptInput
NOTIFICATIONNotification sentMessage
SUBAGENT_STOPSubagent completesResult
SETUPSystem initializationConfig
BEFORE_MESSAGEBefore message processedMessage
AFTER_MESSAGEAfter message processedMessage
MESSAGE_RECEIVEDMessage receivedMessage
MESSAGE_SENDINGBefore message sentMessage
MESSAGE_SENTAfter message sent-
SESSION_STARTSession beginsContext
SESSION_ENDSession ends-
BEFORE_COMPACTIONBefore context compactionContext
AFTER_COMPACTIONAfter context compactionContext
TOOL_RESULT_PERSISTBefore tool result storedResult
ON_ERRORError occurredError handling
ON_RETRYRetry attemptedRetry config
GATEWAY_STARTGateway startsConfig
GATEWAY_STOPGateway stops-

Single-File Plugins

Create plugins as simple Python files with WordPress-style headers. This is the simplest way to create plugins.

Plugin Header Format

"""
Plugin Name: Weather Tools
Description: Get weather information for any location
Version: 1.0.0
Author: Your Name
Hooks: before_tool, after_tool
Dependencies: requests
"""

from praisonaiagents import tool

@tool
def get_weather(location: str) -> str:
    """Get current weather for a location."""
    return f"Weather for {location}: Sunny, 72°F"

CLI Commands

Manage single-file plugins from the command line:
# Create a new plugin with template
praisonai plugins init my_plugin

# With options
praisonai plugins init weather_tools --author "John Doe" --with-hook

# In a specific directory
praisonai plugins init custom --output ./my_plugins/

Discovery and Loading

from praisonaiagents import (
    discover_plugins,
    load_plugin,
    discover_and_load_plugins,
    get_default_plugin_dirs,
)

# Discover plugins without loading
plugins = discover_plugins()
for p in plugins:
    print(f"{p['name']} v{p['version']}")

# Load a specific plugin
metadata = load_plugin("./plugins/weather.py")
print(f"Loaded: {metadata['name']}")

# Discover and load all plugins at once
all_plugins = discover_and_load_plugins()

# Get default plugin directories
# Returns: ['./.praisonai/plugins/', '~/.praisonai/plugins/']
dirs = get_default_plugin_dirs()

Plugin Directories

Plugins are discovered from these directories (in precedence order):
DirectoryScope
./.praisonai/plugins/Project-specific
~/.praisonai/plugins/User-wide

Generate Plugin Template

from praisonaiagents import get_plugin_template, ensure_plugin_dir

# Generate a plugin template
template = get_plugin_template(
    name="My Plugin",
    description="Does something useful",
    author="Your Name"
)

# Ensure user plugin directory exists
plugin_dir = ensure_plugin_dir()  # Creates ~/.praisonai/plugins/

Folder Structure

praisonaiagents/plugins/
├── __init__.py           # Public exports
├── protocols.py          # Plugin protocols
├── manager.py            # PluginManager
├── plugin.py             # Plugin base class
├── parser.py             # Single-file header parser
├── discovery.py          # Plugin discovery
├── sdk/                  # Plugin SDK
│   ├── __init__.py
│   └── decorators.py
└── builtin/              # Built-in plugins
    ├── __init__.py
    ├── logging_plugin.py
    └── metrics_plugin.py

Examples

from praisonaiagents import PluginManager, FunctionPlugin, PluginHook

def log_tool_calls(tool_name, args):
    print(f"Tool: {tool_name}, Args: {args}")
    return args

plugin = FunctionPlugin(
    name="logger",
    hooks={PluginHook.BEFORE_TOOL: log_tool_calls}
)

manager = PluginManager()
manager.register(plugin)

Performance

Plugins use lazy loading and have zero overhead when not used. All imports are deferred until the plugin is actually accessed.
# This import is instant - no plugins loaded yet
from praisonaiagents.plugins import PluginManager

# Plugins only load when registered
manager = PluginManager()
manager.register(LoggingPlugin())  # LoggingPlugin loads here

Thread Safety

plugins.enable(...), plugins.disable(...) and plugins.is_enabled(...) are protected by an internal lock, so they’re safe to call from multiple threads — for example from a FastAPI worker pool or a Celery task. The lock also protects against time-of-check/time-of-use races during discovery.
Plugin enable/disable operations are thread-safe, making them suitable for multi-threaded web applications and background job processors.