Quick Start¶
Get up and running with PKL in minutes!
Your First Plugin¶
Let's create a simple plugin that logs messages.
1. Create Plugin Structure¶
2. Create Metadata File¶
Create plugin.json:
3. Create Plugin Code¶
Create plugin.py:
from pkl import log, event
# Plugin initialization code runs when enabled
log.info("My plugin is starting!")
# Create an event
@event()
def on_message(text: str):
"""Event fired when a message is received."""
log.info(f"Before handlers: {text}")
yield # Handlers run here
log.info(f"After handlers: {text}")
4. Create Plugin API¶
Create __init__.py:
from pkl import syscall, get_current_plugin
@syscall
def send_message(text: str):
"""Public API to send a message."""
# This runs in my_plugin's context
from . import plugin
plugin.on_message(text)
@syscall
def get_plugin_name() -> str:
"""Get the name of this plugin."""
return get_current_plugin().name
5. Load and Use the Plugin¶
Create main.py in the parent directory:
import pkl
from pathlib import Path
# Create a plugin host
host = pkl.PluginHost()
pkl.set_default_host(host)
# Load and enable your plugin
plugin = pkl.load_plugin(Path("./my_plugin"))
plugin.enable()
# Use the plugin's API
from pkl.plugins import my_plugin
# Call the API
name = my_plugin.get_plugin_name()
print(f"Plugin name: {name}")
# Subscribe to the event
@plugin.module.on_message.on
def on_msg(text: str):
print(f"Handler received: {text}")
# Trigger the event via API
my_plugin.send_message("Hello, PKL!")
# Clean up
plugin.disable()
print("Plugin disabled - all resources cleaned up!")
6. Run It!¶
You should see output like:
2026-03-04 10:30:00,123 - INFO - [my_plugin] My plugin is starting!
Plugin name: my_plugin
2026-03-04 10:30:00,124 - INFO - [my_plugin] Before handlers: Hello, PKL!
Handler received: Hello, PKL!
2026-03-04 10:30:00,125 - INFO - [my_plugin] After handlers: Hello, PKL!
Plugin disabled - all resources cleaned up!
What Just Happened?¶
- Plugin created - With metadata, code, and API
- Host initialized - The plugin management system
- Plugin loaded - Code was loaded and prepared
- Plugin enabled - Initialization code ran
- API called - Function ran in plugin's context
- Event subscribed - Handler automatically registered as resource
- Event triggered - Via the public API (enforces owner-only invocation)
- Plugin disabled - All resources (handler, logger) automatically cleaned up
Key Concepts Demonstrated¶
@event()- Creates events with before/after hooks@syscall- Preserves plugin context across callslog- Per-plugin logging with automatic cleanup- Resource management - Automatic tracking and cleanup
Next Steps¶
- Core Concepts - Understand the architecture
- Creating Plugins - Learn plugin best practices
- Events - Master the event system
- Examples - See more complex examples