Skip to content

Building plugins

killown edited this page Jan 16, 2026 · 4 revisions

Building plugins with AI

This document explains how to use the scraper.py tool to generate a context file that allows an AI to build Waypanel plugins while adhering to strict architectural rules.

  1. Generate the Context File

Run the script from your terminal at the project root. python3 tools/scraper.py --input . --output waypanel_context.txt

Parameters:

--input: Directory to scan (default: .)
--output: Resulting filename (default: python_code.txt)

2. Upload to AI Interface

Open your AI assistant (Gemini, Claude, or ChatGPT).
Upload the generated waypanel_context.txt.
The file contains a Strict Instruction Set header ensuring the AI respects Waypanel’s "no top-level imports" architecture.

3. Prompting for New Plugins

Use a specific prompt to trigger the logic contained in the file:

"I have uploaded the Waypanel source code. Using the provided rules and the BasePlugin structure found in the context, create a new plugin that displays system RAM usage."

4. Verification & Installation

The AI will return a code block formatted within the project's delimiters.

Copy the code into a new file.

Ensure the metadata ID is unique.

Follow the installation steps below.

5. Plugin Installation

The plugin architecture is simple; it usually consists of a single file. To install:

Copy the plugin file to ~/.local/share/waypanel/plugins/.

Restart the panel.

If the code is correct, the plugin will be active immediately.

Share Your Creation

If you have developed a plugin that would be useful to others, consider submitting it to the Waypanel Plugins Extra repository.

We encourage community contributions—simply submit a Pull Request to the community/ folder.

────────────────────────────────────────────────────────

Waypanel Plugin Development

This tutorial explains how to build a plugin that interacts with the Waypanel configuration system and manages its own lifecycle using timers.

STRICT ARCHITECTURAL REQUIREMENT: No library imports are allowed at the top level. All imports must be deferred inside get_plugin_class() to support lazy loading.

1. The Metadata Factory

Every plugin must define get_plugin_metadata(panel). This tells Waypanel how to register the plugin and where to place it in the UI containers.

def get_plugin_metadata(panel):
    id = "org.waypanel.plugin.setting_timer_example"
    default_container = "top-panel-center"

    # Fetches user-defined placement or uses the default
    container, id = panel.config_handler.get_plugin_container(default_container, id)

    return {
        "id": id,
        "name": "Setting Timer Example",
        "version": "1.0.0",
        "enabled": True,
        "index": 99,
        "container": container,
        "description": "A demonstration plugin for managing settings over time.",
    }

2. The Class Factory

The get_plugin_class() function returns the implementation class. This is where you perform all imports from the BasePlugin and other modules.

def get_plugin_class():
    from src.plugins.core._base import BasePlugin

    class SettingTimerExample(BasePlugin):
        def __init__(self, panel_instance):
            super().__init__(panel_instance)
            self._timer_id = None
            self._label = self.gtk.Label()
            self._label.add_css_class("example-plugin-label")

        def on_start(self):
            """Entry point for plugin logic"""
            self.logger.info("Plugin started.")

            # Define initial data
            initial_data = {"status": "active", "message": "Self-destructing..."}

            # 1. Save setting and add a hint for the Control Center
            self.get_plugin_setting_add_hint(
                ["session_data"], 
                initial_data, 
                "Used to demonstrate dynamic settings cleanup"
            )

            # 2. Schedule cleanup in 10 seconds using the GLib helper
            self._timer_id = self.glib.timeout_add_seconds(10, self._remove_setting_callback)

            # 3. Mount the widget to the panel
            self.main_widget = (self._label, "append")

        def _remove_setting_callback(self):
            """Timer callback for data removal"""
            self.remove_plugin_setting() # Clears entire plugin config section
            self._label.set_text("Setting removed.")
            self._timer_id = None
            return self.glib.SOURCE_REMOVE

        def on_disable(self):
            """Cleanup when the plugin is stopped"""
            if self._timer_id:
                self.glib.source_remove(self._timer_id)
                self._timer_id = None

    return SettingTimerExample

3. Core API Reference

The BasePlugin provides high-level access to system resources without needing manual imports:

self.get_plugin_setting_add_hint()

Saves a config value and provides help text for the UI.

self.remove_plugin_setting()

Deletes the plugin's configuration section from disk.

self.main_widget

Tuple (widget, action) to display the plugin on the panel.

For detailed examples, visit: Plugin Examples