How to Define a Custom Plugin manifest.json for Omarchy: Complete Developer Guide

Omarchy discovers and loads plugins through a manifest.json file placed in the plugin's root directory, which supplies metadata and entry-point mappings required by the Quickshell runtime.

Omarchy is a desktop environment built on the Quickshell runtime that extends functionality through a dynamic plugin system. When the shell starts, it scans specific directories for valid plugin manifests. Understanding how to define a custom plugin manifest.json for Omarchy is essential for extending the desktop with custom bar widgets, panels, or background services.

How Omarchy Discovers Plugins

The plugin discovery mechanism is implemented in shell/PluginManager.qml. When Quickshell initializes, the manager searches the shell/plugins/ directory for subdirectories containing a manifest.json file. The loadPluginManifest function parses this JSON to register the plugin under its unique identifier and create the appropriate QML components.

Each manifest must reside in the plugin's root directory. For reference, see the Weather panel implementation at shell/plugins/panels/weather/manifest.json. The runtime uses the manifest to determine which kinds the plugin implements and which QML files to load for each entry point.

Required Manifest Schema Fields

A valid manifest.json must include specific metadata fields that tell Omarchy how to handle the plugin:

  • schemaVersion: Currently must be set to 1
  • id: A unique dotted identifier (e.g., "omarchy.weather") used to reference the plugin globally
  • name: Human-readable title displayed in the UI
  • kinds: Array of plugin types implemented (e.g., ["bar-widget"], ["panel"], or ["service"])
  • entryPoints: Object mapping each kind to its corresponding QML file path relative to the plugin directory

Optional fields include version, author, and description, which appear in the plugin picker interface.

Configuring Plugin Entry Points and Kinds

The entryPoints object defines which QML files the runtime loads for each kind. For example, a bar widget declares "barWidget": "BarWidget.qml" to specify that BarWidget.qml contains the implementation extending the base component found in shell/components/BarWidget.qml.

Kind-specific metadata blocks (e.g., barWidget, panel) configure UI presentation:

  • displayName: The title shown in selection menus
  • category: The grouping for organization (e.g., "Utility", "System")
  • allowMultiple: Boolean indicating whether users can instantiate multiple copies
  • settingsForm: String referencing a QML file (relative path) that extends shell/components/SettingsForm.qml for configuration UI

Creating a Custom Plugin Step-by-Step

Follow this workflow to register a new plugin with Omarchy:

  1. Create a directory under shell/plugins/ (e.g., shell/plugins/panels/my-awesome-panel/)
  2. Add a manifest.json with required fields and appropriate kinds
  3. Create the QML files referenced in entryPoints relative to the plugin directory
  4. Optionally create a settings form QML and reference it in the kind-specific block
  5. Restart Omarchy to trigger plugin scanning

Minimal Bar-Widget Plugin Example

This complete example demonstrates a functional custom widget.

The manifest.json file:

{
  "schemaVersion": 1,
  "id": "omarchy.mywidget",
  "name": "My Widget",
  "version": "0.1.0",
  "author": "Your Name",
  "description": "A simple custom bar widget",
  "kinds": ["bar-widget"],
  "entryPoints": {
    "barWidget": "MyBarWidget.qml"
  },
  "barWidget": {
    "displayName": "My Widget",
    "description": "Shows a static label",
    "category": "Utility",
    "allowMultiple": false,
    "settingsForm": "myWidgetSettings"
  }
}

The corresponding MyBarWidget.qml implementation:

import QtQuick 2.15
import Omarchy 1.0

BarWidget {
    Text {
        text: "Hello Omarchy"
        color: Theme.foreground
    }
}

Optional settings form (myWidgetSettings.qml):

import QtQuick 2.15
import Omarchy 1.0

SettingsForm {
    property string greeting: "Hello Omarchy"
}

Place all three files in the same plugin directory. After restarting Omarchy, the new widget appears under Utility → My Widget in the bar-widget picker.

Summary

  • Omarchy scans shell/plugins/ directories for manifest.json files during startup via shell/PluginManager.qml
  • The manifest requires schemaVersion, id, name, kinds, and entryPoints at minimum
  • Kind-specific blocks configure UI metadata like displayName, category, and allowMultiple
  • Entry points reference QML files that extend base components such as BarWidget or SettingsForm
  • Plugins must be placed in the correct directory structure and require a shell restart to appear in the interface

Frequently Asked Questions

What kinds of plugins can I create in Omarchy?

Omarchy supports several plugin kinds including bar-widget for the top bar, panel for full-screen overlays, and service for background processes. Each kind expects specific entry point names in the manifest and extends corresponding base components in shell/components/.

Where does Omarchy scan for plugin manifests?

The runtime scans subdirectories within shell/plugins/ looking for manifest.json files. The discovery logic resides in shell/PluginManager.qml. You can organize plugins into subdirectories like shell/plugins/panels/ or shell/plugins/services/ without affecting detection.

Can I instantiate multiple copies of the same widget?

Set allowMultiple: true in the kind-specific configuration block (e.g., barWidget.allowMultiple). When enabled, users can add multiple instances of your plugin to the bar or panel. If set to false, the system restricts instantiation to a single copy.

How do I debug a plugin that isn't loading?

Verify that manifest.json contains valid JSON with all required fields (schemaVersion, id, name, kinds, entryPoints). Check that QML file paths in entryPoints are correct relative to the plugin directory. Omarchy's startup logs often indicate parse errors in shell/PluginManager.qml if the manifest fails validation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →