Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ryzhpolsos/redeye/llms.txt

Use this file to discover all available pages before exploring further.

A RedEye plugin is a directory containing a plugin.json manifest and one or more .cs source files. The C# files are compiled at startup, and any class that subclasses Plugin is instantiated automatically. This guide walks through creating a minimal working plugin.
1

Create the plugin directory

Inside the RedEye application directory, create a folder under plugins/ using your plugin’s ID as the name. The ID must be unique and will prefix all exported widget and function names.
mkdir "C:\RedEye\plugins\my-plugin"
Replace C:\RedEye with your actual RedEye installation directory.
The directory name becomes the plugin ID. Use lowercase kebab-case to keep exported names readable: my-plugin.widgetName, my-plugin.functionName.
2

Create plugin.json

Add a plugin.json manifest to the directory. At minimum, provide id and name. Add requiredAssemblies if your code uses assemblies not already loaded by RedEye, and list dependencies if this plugin must load after another.
{
  "id": "my-plugin",
  "name": "My Plugin"
}
An example with optional fields:
{
  "id": "my-plugin",
  "name": "My Plugin",
  "requiredAssemblies": [
    "System.Net.Http"
  ],
  "dependencies": [
    "shared-utils"
  ]
}
3

Create a .cs file and extend Plugin

Create a .cs file in the plugin directory. Define a class that extends RedEye.PluginAPI.Plugin. You do not need to add a namespace, but it helps avoid name collisions with other plugins.
using RedEye.PluginAPI;

namespace MyPlugin {
    public class MyPlugin : Plugin {
        public override void Main() {
            Logger.LogInformation("MyPlugin loaded!");
        }
    }
}
The Plugin base class injects all RedEye services as protected properties before Main() is called, so Logger, Config, HotKeyManager, and the rest are ready to use immediately.
4

Register widgets and functions in Main()

Call ExportWidget<T>(name) to make a widget type available in RWML, and ExportFunction(name, func) to add a callable expression function. Both methods automatically prefix the name with the plugin ID.
using RedEye.PluginAPI;

namespace MyPlugin {
    public class MyPlugin : Plugin {
        public override void Main() {
            // Registers the widget as "my-plugin.clock"
            ExportWidget<ClockWidget>("clock");

            // Registers the function as "my-plugin.formatTime"
            ExportFunction("formatTime", (args, vars) => {
                var input = args.ElementAt(0)?.ToString() ?? string.Empty;
                return DateTime.TryParse(input, out var dt)
                    ? dt.ToString("HH:mm")
                    : string.Empty;
            });
        }
    }
}
You can export multiple widgets and multiple functions from a single Main() call.
5

Restart RedEye to load the plugin

RedEye compiles and loads plugins at startup only. Save your files and restart the shell. Watch the log output: a successful load prints Loaded plugin: my-plugin. If there are C# compilation errors, all error messages and line numbers appear in the log.
A compilation error in any plugin halts the entire plugin loader. All plugins after the failing one in the load order will not be loaded until the error is fixed.

Dependency resolution

When a plugin lists dependencies in its manifest, the loader checks whether each dependency has already been loaded. If not, the plugin is moved to the end of the load queue and the loop continues. This repeats until all dependencies are satisfied or a missing dependency is detected — in which case loading halts with a fatal log entry.
{
  "id": "advanced-taskbar",
  "name": "Advanced Taskbar",
  "dependencies": ["shared-utils", "theme-engine"]
}
Circular dependencies are not detected and will cause an infinite loop. Ensure your dependency graph is acyclic.

Complete minimal plugin example

using System.Linq;
using RedEye.PluginAPI;

namespace MyPlugin {
    public class MyPlugin : Plugin {
        public override void Main() {
            Logger.LogInformation($"Plugin \"{Name}\" started");

            ExportFunction("greet", (args, vars) => {
                var who = args.ElementAt(0)?.ToString() ?? "world";
                return $"Hello, {who}!";
            });
        }
    }
}
With the above plugin in plugins/my-plugin/, after restarting you can call my-plugin.greet("RedEye") from any RWML expression attribute.

Build docs developers (and LLMs) love