Skip to main content
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