Skip to main content

Writing a plugin

A plugin is a self-contained directory the gateway discovers at runtime. It can ship a connector, a controller, a channel, a processor, and/or extra tools — any subset.

Layout

youkore-myplugin/
├── plugin.json manifest
├── README.md
└── src/
├── __init__.py
├── connector.py (optional) BaseConnector subclass
├── controller.py mandatory — the BaseController subclass
├── channel.py (optional, channel-style only)
├── processor.py (optional, channel-style only)
└── tools.py (optional) extra TOOL_DEFINITIONS

Manifest

The manifest mirrors the format used by built-in integrations. Below is a real example (Discord plugin), abridged:

{
"id": "youkore-myplugin",
"name": "My Plugin",
"version": "0.1.0",
"description": "What it does, in one line.",
"author": "you",

"provides": {
"connector": {
"id": "myplugin",
"name": "My Plugin",
"icon": "message-square",
"description": "Short user-facing blurb.",
"class": "connector:MyConnector",
"controller_class": "controller:MyController",
"auth_type": "credentials",
"connect_fields": [
{"key": "api_key", "label": "API Key", "type": "password"}
],
"status_fields": [
{"key": "workspace", "label": "Workspace"}
],
"setting_fields": [
{"key": "default_agent", "label": "Default agent", "type": "select", "options_from": "agents"}
]
},
"channel": {
"id": "myplugin",
"class": "channel:MyChannel"
},
"processor": {
"id": "myplugin",
"class": "processor:MyProcessor"
},
"tools_module": "tools"
},

"credentials": ["myplugin_api_key"],

"requirements": {
"some-pypi-package": ">=1.0"
}
}

Notes:

  • Class paths are module:ClassName, relative to the plugin's src/ package
  • connect_fields, status_fields, setting_fields are nested inside provides.connector and drive the Flutter integration editor automatically
  • requirements is a dict of package: version_spec, not a list — used to build the per-plugin venv on first load
  • For tool-only or service-style plugins, omit channel and processor

Local install for development

Drop the directory into ~/.youkore/plugins/. The gateway picks it up at next start, or via IntegrationManager.reload_connector for hot-plug.

Per-plugin venv

If requirements is non-empty, the gateway creates an isolated venv at first load and installs them via the bundled Python sidecar. No conflicts with the main runtime.

Custom tools in your plugin

Drop a tools.py (or whatever you set as tools_module) that exports TOOL_DEFINITIONS — same shape as the built-in src/tools/* modules. They're picked up by ToolManager once the plugin is loaded.

Building and signing for distribution

# 1) Compile (Nuitka, optional — for closed-source plugins)
python build/build_plugin.py youkore-myplugin

# 2) Sign the bundle with your private key (offline, on USB)
python build/sign_plugin.py youkore-myplugin-0.1.0 --key /path/to/plugin.key

# 3) Upload (admin only — coming with build/release.py)

The plugins-worker rejects any upload whose .yk.sig doesn't verify against the embedded public key.

Public submission flow

Coming. Plan: open a PR on the foundation's plugin repo → review → cosigned and published. Until then, plugins are first-party only.