Skip to main content

Plugin System

l3mcore implements a plugin architecture based on Hooks that allows extending functionality without touching the core code.

How it works

Any .py file in the plugins/ folder is automatically imported when starting l3mcore.

lemoe/
└── plugins/
├── email_masker.py ← loaded automatically
├── audit_logger.py ← loaded automatically
└── rag_enhancer.py ← loaded automatically
Silent loading

If a plugin has syntactic errors, l3mcore registers it in the log and continues working without crashing.

Available hooks

before_routing(prompt: str) -> str

Executed before the ML router vectorizes the prompt.

Uses: PII censorship, prompt injection blocking, RAG enrichment, automatic translation.

def before_routing(prompt: str) -> str:
# Your logic here
return modified_prompt # must return string

after_generation(response: str) -> str

Executed after the expert generates the response, before sending it to the client.

Uses: output formatting, response censorship, signature injection, JSON validation.

def after_generation(response: str) -> str:
# Your logic here
return modified_response # must return string

Example: Data Masking (PII)

# plugins/email_masker.py
import re

EMAIL_REGEX = r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+'

def before_routing(prompt: str) -> str:
"""Hides emails before sending to the cloud model."""
return re.sub(EMAIL_REGEX, '[HIDDEN_EMAIL]', prompt)

def after_generation(response: str) -> str:
"""Adds a note if the model mentions the placeholder."""
if '[HIDDEN_EMAIL]' in response:
response += "\n\n*(Email addresses have been protected for privacy.)*"
return response

Example: Audit Logger

# plugins/audit_logger.py
import logging
from datetime import datetime

audit_log = logging.getLogger('lemoe.audit')

def before_routing(prompt: str) -> str:
"""Logs all requests to the audit log."""
audit_log.info(f"[{datetime.now().isoformat()}] PROMPT_RECEIVED: {len(prompt)} chars")
return prompt # unmodified

def after_generation(response: str) -> str:
audit_log.info(f"[{datetime.now().isoformat()}] RESPONSE_SENT: {len(response)} chars")
return response

Example: RAG Enrichment

# plugins/rag_enhancer.py
import requests

RAG_API_URL = "http://localhost:8000/search"

def before_routing(prompt: str) -> str:
"""Adds relevant context from your knowledge base."""
try:
r = requests.post(RAG_API_URL, json={"query": prompt}, timeout=2)
if r.ok:
context = r.json().get("context", "")
if context:
return f"Relevant context:\n{context}\n\nQuestion: {prompt}"
except Exception:
pass # If RAG fails, return the original prompt
return prompt

Best practices

  1. Speed: Hooks are synchronous. If you make HTTP requests, use low timeouts (≤2s).
  2. Error handling: Always wrap in try/except and return the original input in case of failure.
  3. Independence: Do not import internal l3mcore modules. Work with pure strings.
  4. Idempotence: The after_generation hook can be called in streaming chunks — design with that in mind.

Plugin repository

Official l3mcore plugins are available on GitHub:

github.com/lemoelink/plugins

To install a plugin, download the corresponding .py file and copy it into the plugins/ folder of your l3mcore installation. The server will load it on the next start.

Available plugins

PluginRepositoryHookDescription
Multimodal Plugin (Images)image_router.pyoverride_routeAutomatically routes image requests to a vision expert like LLaVA or GPT-4o.
System Time Pluginsystem_time.pyoverride_routeAutomatically injects the current local system date and time into the initial context.
User Profile Pluginuser_profile.pyoverride_routeInjects the user's name, preferences, and custom instructions into the initial context.