Skip to content

Plugin Integration

SimpleContext-Bot v1.2 has a fully dynamic plugin system. Any plugin dropped into the plugins/ folder is auto-loaded, and its app_commands are automatically registered as Telegram commands.


How It Works

On every start, the bot:

  1. Scans all .py files in ~/.simplecontext-bot/plugins/
  2. Loads any class that inherits BasePlugin
  3. Reads app_commands from each loaded plugin
  4. Registers each command as a Telegram handler
  5. Sets bot command menu via set_my_commands()
  6. Injects app_info into all plugins: {"platform": "telegram", "version": "1.2.0"}

No changes to bot code needed — ever.


Install a Plugin

simplecontext-bot plugins install vector-search
simplecontext-bot start   # new commands registered on next start
# Copy any .py plugin file — community or your own
cp my_plugin.py ~/.simplecontext-bot/plugins/
simplecontext-bot start

Plugin Lifecycle in Bot

simplecontext-bot start
_load_all_plugins()
  ├── scan plugins/*.py
  ├── load each BasePlugin subclass
  ├── inject config from config.json
  └── sc.use(plugin_instance)
_collect_app_commands()
  └── sc._plugins.get_all_app_commands()
For each command:
  └── app.add_handler(CommandHandler(cmd_name, handler_fn))
post_init: bot.set_my_commands([...static..., ...plugin cmds...])
Bot running ✅

Writing a Plugin for SimpleContext-Bot

Any plugin that declares app_commands will have its commands registered:

from simplecontext.plugins.base import BasePlugin, AppCommandContext

class MyPlugin(BasePlugin):
    name        = "my_plugin"
    version     = "1.0.0"
    description = "My plugin description."

    app_commands = {
        "mycommand": {
            "description": "What /mycommand does",
            "usage":       "/mycommand <arg>",
            "handler":     "handle_mycommand",
        }
    }

    def on_context_build(self, user_id, messages):
        # This hook runs for every message automatically
        messages[0]["content"] += "\n\nExtra context."
        return messages

    async def handle_mycommand(self, ctx: AppCommandContext) -> str:
        # ctx.platform == "telegram"
        # ctx.user_id  == Telegram user ID string
        # ctx.args_str == everything after /mycommand
        return f"Hello from Telegram! You said: {ctx.args_str}"

Drop my_plugin.py into ~/.simplecontext-bot/plugins/ and restart. /mycommand is now live.


Accessing Platform-Specific Data

The ctx.raw field contains the Telegram Update object:

async def handle_mycommand(self, ctx: AppCommandContext) -> str:
    # Access Telegram-specific data
    update = ctx.raw
    user   = update.effective_user
    chat   = update.effective_chat

    return f"Hello {user.first_name} in chat {chat.id}!"

Keep plugins platform-agnostic when possible

Use ctx.user_id, ctx.args_str, and ctx.sc for logic that should work on any platform. Only access ctx.raw for Telegram-specific features.


Checking App Info

def setup(self):
    # Check which platform loaded this plugin
    platform = self.app_info.get("platform", "unknown")
    version  = self.app_info.get("version", "unknown")
    print(f"Loaded on {platform} v{version}")

Plugin Config in Bot

Plugin config is stored in ~/.simplecontext-bot/config.json under plugins.configs:

{
  "plugins": {
    "enabled": true,
    "installed": ["vector-search"],
    "configs": {
      "vector-search": {
        "provider": "local",
        "top_k": 5,
        "min_score": 0.15,
        "tiers": ["semantic", "episodic"]
      }
    }
  }
}

Edit this file to customize plugin config, then restart the bot.