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 viaBar.qmlbar-widget: Provides a widget that attaches to existing bars viaBarWidget.qmlpanel: Creates detachable overlay panels viaPanel.qmlservice: Runs background processes without UI viaService.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:
shell/plugins/– Built-in plugins shipped with Omarchy~/.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
idfield must not contain..or/characters to prevent directory traversal - Kind Array: The
kindsproperty 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 metadataenablePlugin: Activates a plugin in the registrydisablePlugin: 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.jsonand QML implementation files discovered atshell/plugins/and~/.config/omarchy/plugins/. - Strict Validation: The
omarchy-plugin-validateroutine enforces ID safety, kind existence, and entry point mapping before registration. - Kind System: Plugins declare capabilities as
bar,bar-widget,panel, orservice, 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, andomarchy-plugin-cloneprovide 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →