How Omarchy's Plugin Architecture Works: A Technical Deep Dive

Omarchy implements a folder-based plugin system where each extension is defined by a manifest.json file, validated at startup, and loaded dynamically into a registry that maps QML entry points to specific UI kinds like bars, widgets, panels, and background services.

Omarchy, the open-source desktop environment from Basecamp, treats every extension as a first-class plugin governed by a strict contract. The Omarchy plugin architecture enables third-party customization through a declarative manifest system that separates core shell logic from user-defined functionality. By leveraging runtime discovery and hot-reload capabilities, the system allows developers to iterate on QML-based components without restarting the desktop session.

Core Plugin Concepts

The foundation of Omarchy's extensibility rests on two pillars: the plugin manifest and kind-based entry points. Every plugin operates as an isolated directory containing metadata and implementation files.

Plugin Manifest Structure

Each plugin folder must contain a manifest.json file that declares the plugin's identity and capabilities. According to the source code in shell/plugins/bar/manifest.json, the manifest specifies:

  • ID: A unique identifier (e.g., omarchy.weather)
  • Name: Human-readable display name
  • Kinds: An array defining which UI patterns the plugin implements
  • EntryPoints: A mapping that connects each kind to its QML implementation file

The manifest also includes optional UI metadata such as displayName, category, and settingsForm, which the shell uses to render configuration interfaces.

Supported Plugin Kinds

Omarchy recognizes four distinct plugin kinds, each corresponding to a specific QML file pattern:

  • bar: Implements a full status bar via Bar.qml
  • bar-widget: Provides a widget that attaches to existing bars via BarWidget.qml
  • panel: Creates detachable overlay panels via Panel.qml
  • service: Runs background processes without UI via Service.qml

As seen in the weather plugin manifest at shell/plugins/panels/weather/manifest.json, a single plugin can declare multiple kinds, though each requires a matching entry point in the entryPoints object.

Plugin Discovery and Validation

Omarchy employs a dual-path discovery mechanism that scans both built-in system plugins and user-space extensions.

Directory Scanning

At startup, the shell recursively walks two directories:

  1. shell/plugins/ – Built-in plugins shipped with Omarchy
  2. ~/.config/omarchy/plugins/ – User-installed third-party extensions

Every immediate subfolder containing a manifest.json is considered a plugin candidate. The test suite in plugins-test.sh enforces that every top-level folder under the plugins directory must include a valid manifest.

Manifest Validation

Before registration, each candidate undergoes strict validation via the omarchy-plugin-validate routine. As documented in test/shell.d/plugin-validate-test.sh, the validator performs the following checks:

  • ID Safety: The id field must not contain .. or / characters to prevent directory traversal
  • Kind Array: The kinds property must be a non-empty array
  • Entry Point Existence: Every declared kind must have a corresponding entry in entryPoints
  • Uniqueness: No duplicate kind definitions are permitted within a single manifest

Any validation failure aborts the loading process for that specific plugin, ensuring the registry contains only well-formed extensions.

Plugin Registration and Runtime

Once validated, plugins transition into the active runtime environment through an in-memory registry system.

In-Memory Registry

The plugin registry maintains a live mapping of kinds to their QML entry points. It stores the file paths to implementation files (e.g., BarWidget.qml) and associated metadata. This registry drives the shell's IPC command set:

  • listPlugins: Returns all registered plugins with their metadata
  • enablePlugin: Activates a plugin in the registry
  • disablePlugin: Deactivates a plugin without deleting its files

The contract between the registry and IPC layer is verified by test/shell.d/plugin-registry-contract-test.sh, ensuring consistent behavior across shell restarts.

Hot-Reload Mechanism

Omarchy monitors all plugin directories for filesystem changes. When a developer modifies a QML file or manifest.json within ~/.config/omarchy/plugins/, the shell automatically reloads that specific plugin. As noted in test/shell.d/runtime-smoke-test.sh, this hot-reload preserves application state where possible, enabling rapid development iteration without desktop restarts.

CLI Integration and User Workflows

The Omarchy CLI provides three primary commands for plugin lifecycle management, implemented as wrappers around the registry API.

Enabling and Disabling Plugins

Users control plugin activation through shell commands:


# Activate the weather widget

omarchy-plugin-enable omarchy.weather

# Deactivate the plugin

omarchy-plugin-disable omarchy.weather

These commands update the active registry and adjust the UI layout according to the manifest's default placement rules. The plugin-enable-test.sh suite verifies that enabled plugins correctly register their entry points and appear in the listPlugins IPC response.

Cloning Existing Plugins

The omarchy-plugin-clone command copies an installed plugin into the user configuration directory:

omarchy-plugin-clone omarchy.weather

This command, tested in plugin-clone-test.sh, preserves dependencies and metadata while creating an editable copy at ~/.config/omarchy/plugins/, allowing users to customize built-in functionality without modifying system files.

Building a Custom Plugin

Creating a custom extension requires three components: a directory, a manifest, and a QML implementation file.

Directory Structure

Create a folder under the user plugins directory:


~/.config/omarchy/plugins/my.example/
├─ manifest.json
└─ BarWidget.qml

Manifest Definition

Create manifest.json with the following structure:

{
  "schemaVersion": 1,
  "id": "my.example",
  "name": "Example Widget",
  "version": "0.1.0",
  "author": "Me",
  "description": "A simple bar-widget example",
  "kinds": ["bar-widget"],
  "entryPoints": { "barWidget": "BarWidget.qml" },
  "barWidget": {
    "displayName": "Example",
    "category": "Demo",
    "allowMultiple": false
  }
}

QML Implementation

Create BarWidget.qml containing the widget logic:

import QtQuick 2.15
import QtQuick.Controls 2.15

Item {
    width: 100; height: 24
    Text { anchors.centerIn: parent; text: "Hello!" }
}

Activation

Enable the plugin via CLI:

omarchy-plugin-enable my.example

The shell reads the manifest, registers the barWidget entry point, and instantiates the QML component on the default bar.

Summary

  • Folder-Based Architecture: Every plugin is a directory containing manifest.json and QML implementation files discovered at shell/plugins/ and ~/.config/omarchy/plugins/.
  • Strict Validation: The omarchy-plugin-validate routine enforces ID safety, kind existence, and entry point mapping before registration.
  • Kind System: Plugins declare capabilities as bar, bar-widget, panel, or service, each mapping to specific QML file patterns.
  • Hot-Reload: Filesystem watchers enable automatic reloading of plugins in ~/.config/omarchy/plugins/ without shell restarts.
  • CLI Management: Commands like omarchy-plugin-enable, omarchy-plugin-disable, and omarchy-plugin-clone provide safe manipulation of the active registry.

Frequently Asked Questions

What file structure is required for an Omarchy plugin?

An Omarchy plugin requires a dedicated folder containing a manifest.json file at the root and QML implementation files referenced in the manifest's entryPoints object. The folder must reside in either shell/plugins/ for system extensions or ~/.config/omarchy/plugins/ for user extensions. The manifest defines the plugin ID, supported kinds, and UI metadata, while the QML files provide the actual implementation for each declared capability.

How does Omarchy validate plugin manifests before loading?

Omarchy validates manifests through the omarchy-plugin-validate routine, which checks that the plugin ID contains no directory traversal characters (.. or /), that the kinds array is non-empty, and that every kind has a matching entry point defined in entryPoints. The validator also ensures no duplicate kind definitions exist within a single manifest. Any validation failure prevents the plugin from entering the in-memory registry, protecting the shell from malformed extensions.

Can I modify a plugin without restarting the Omarchy desktop?

Yes. Omarchy implements a hot-reload mechanism that watches all plugin directories for changes. When you modify a QML file or manifest.json within a plugin folder, particularly in ~/.config/omarchy/plugins/, the shell automatically reloads that specific plugin while preserving application state. This behavior is verified in test/shell.d/runtime-smoke-test.sh and enables rapid development iteration without session restarts.

What is the difference between omarchy-plugin-enable and omarchy-plugin-clone?

omarchy-plugin-enable activates a plugin by adding it to the in-memory registry and placing its UI components according to the manifest defaults, while omarchy-plugin-clone creates a copy of an existing plugin in your user configuration directory. Use enable to activate built-in or already-installed plugins, and use clone when you want to customize an existing plugin without modifying the original system files.

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 →