# How the Quickshell Desktop in Omarchy Works: Architecture and Plugin System

> Explore the Quickshell desktop in Omarchy. Discover its modular QML architecture, dynamic plugin system for bars and widgets, and JSON configuration.

- Repository: [Omacom/omarchy](https://github.com/omacom/omarchy)
- Tags: architecture
- Published: 2026-09-04

---

**The Quickshell desktop in Omarchy is a modular QML-based compositor centered on `shell.qml`, which orchestrates a dynamic plugin system for bars, widgets, and panels through a JSON-driven configuration and IPC handlers.**

Omarchy’s desktop environment is built on **Quickshell**, a QML-based compositor designed for flexibility and extensibility. The system revolves around a central **ShellRoot** defined in `shell/shell.qml`, which manages global state, discovers plugins, and exposes an IPC bridge for external control.

## Core Architecture Components

The architecture follows a registry-based design where functionality is loaded dynamically through manifests rather than hardcoded logic.

### ShellRoot and Global State

The entry point `shell/shell.qml` instantiates a long-running **ShellRoot** object that maintains global application state. This component reads the user’s [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json) configuration, manages hot-reloads, and routes all IPC calls between external tools and the desktop internals. It holds references to the `PluginRegistry`, `BarWidgetRegistry`, and panel loading mechanisms.

### PluginRegistry and Discovery

The `PluginRegistry` (implemented in `shell/services/PluginRegistry.qml`) handles scanning and validation of both first-party and third-party plugins.

- **Scanning**: The `rescan()` method executes a Bash script that emits manifest files found in `$OMARCHY_PATH/shell/plugins` and `~/.config/omarchy/plugins`.
- **Validation**: The `parseScanOutput` function processes results through `validateManifest` to ensure manifests contain required fields (`id`, `kinds`, `entryPoints`) before storing them in `installedPlugins`.
- **State Management**: The registry tracks enabled status and provides `setEnabled(id, true/false, placement)` to modify the active plugin set.

### Bar System and Widgets

The visual bar is implemented in `shell/plugins/bar/Bar.qml`, which renders top or bottom bars and manages widget layout.

- **BarWidgetRegistry**: Located at `shell/services/BarWidgetRegistry.qml`, this service holds concrete QML components for each bar widget and exposes metadata for the settings UI.
- **Layout**: Widget placement follows `shellConfig.bar.layout.{left,center,right}`, defined in the user configuration.
- **Integration**: Widgets declare kind `"bar-widget"` in their manifest; when enabled, the shell creates a `Component` from `entryPoints.barWidget` and registers it with the `BarWidgetRegistry`.

### Services and Panel Loading

**Service plugins** (kind `"service"`) are loaded as singletons into an internal `_services` map. These run as children of an invisible `serviceHost` object and are accessible via `shell.serviceFor(id)`, receiving the same injection properties as panels (`omarchyPath`, `shell`, `manifest`).

**Panels, overlays, and menus** load on-demand through a dynamic system:

1. **Discovery**: `computePanelEntries()` gathers enabled plugins with kinds `"panel"`, `"overlay"`, or `"menu"`.
2. **Instantiation**: A QML `Instantiator` creates delegates containing a `Loader` (`panelLoaders[id]`) for each entry.
3. **Activation**: Calling `shell.summon(id, payload)` sets `openPanelIds[id]`, activating the `Loader` to fetch the QML component from `entryPoints.<kind>`.
4. **Payload Delivery**: If the component loads asynchronously, data queues in `pendingPayloads` until the `open()` method becomes available.

### IPC Handlers for External Control

Two `IpcHandler` objects expose a JSON RPC-style API for external manipulation:

- **`shell`**: Provides commands including `listPlugins`, `listShellConfig`, `toggleBarTransparency`, `enablePlugin`, `putBarWidget`, `moveBarWidget`, `summon`, `hide`, `toggle`, and generic `call`.
- **`image-selector`**: Offers a specialized interface for the image-picker plugin.

These handlers enable the `omarchy` CLI and other tools to control the desktop without direct QML access.

## Configuration Flow

Configuration follows a cascading merge strategy:

1. **Defaults**: The system initializes `builtinShellConfig` with minimal bar layouts and idle settings.
2. **User Config**: A `FileView` loads `~/.config/omarchy/shell.json`.
3. **Merging**: The `applyShellConfig()` function prefers the user file only when it contains valid JSON with `version: 1`; otherwise, it falls back to defaults.
4. **Reactive Updates**: Modifying `shellConfig` triggers `onShellConfigChanged`, causing the `PluginRegistry` to re-evaluate enabled plugins and the bar to rebuild if necessary.

## Plugin System Implementation

Each plugin ships a [`manifest.json`](https://github.com/omacom/omarchy/blob/main/manifest.json) (or `*.manifest.json`) defining:

- **Identity**: `id` field for unique identification.
- **Capabilities**: `kinds` array declaring types (`bar-widget`, `service`, `panel`, `overlay`, `menu`).
- **Entry Points**: `entryPoints` object mapping kinds to QML file URLs.
- **Metadata**: Optional fields like `barWidget` configuration or `keepLoaded` flags.

First-party plugins reside in `$OMARCHY_PATH/shell/plugins` and are implicitly enabled. Third-party plugins require explicit listing in [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json) under `plugins[]` or exclusion via `disabledPlugins[]`. The `setEnabled()` method writes appropriate entries to [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json), handling bar widget placement through the `putBarWidget` logic or top-level plugin activation.

## Practical Usage Examples

### Toggle a Panel from the Terminal

Activate the weather panel using the `shell` IPC handler:

```bash
omarchy launch shell toggle "omarchy.weather" "{}"

```

This invokes `shell.toggle(id, payload)`, which delegates to internal `summon` or `hide` logic based on current visibility state.

### Add a Custom Bar Widget

Insert a widget into the right section after the system tray:

```bash
PLACEMENT='{"section":"right","after":"omarchy.tray"}'
omarchy launch shell putBarWidget "my.custom.widget" "$PLACEMENT"

```

The `putBarWidget` command checks existing placements, validates the widget ID against `BarWidgetRegistry`, and updates `shell.json.bar.layout` before triggering a bar reload.

### Enable a Third-Party Plugin

Activate a community plugin with default placement:

```bash
omarchy launch shell enablePlugin "my.thirdparty.plugin" "{}"

```

This calls `PluginRegistry.setEnabled(id, true, placement)`, which updates `shell.json.plugins[]` and triggers the configuration reload sequence via `onShellConfigChanged`.

## Summary

- **Entry Point**: `shell/shell.qml` serves as the ShellRoot, coordinating all desktop functionality.
- **Plugin Architecture**: A manifest-driven system using `PluginRegistry` supports first-party and third-party extensions via JSON configuration.
- **Dynamic Loading**: Services load as singletons (`shell.serviceFor()`), while panels instantiate on-demand through QML `Loader` objects controlled by `summon()` and `hide()` calls.
- **Configuration**: User settings in `~/.config/omarchy/shell.json` merge with defaults through `applyShellConfig()`, with reactive updates triggering UI rebuilds.
- **External Control**: IPC handlers expose the full API to CLI tools, enabling scriptable desktop management without modifying QML source.

## Frequently Asked Questions

### What file serves as the main entry point for the Omarchy Quickshell desktop?

The primary entry point is `shell/shell.qml`, which instantiates the **ShellRoot** object. This file initializes the `PluginRegistry`, loads user configuration from [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json), sets up IPC handlers, and manages the lifecycle of bars, services, and panels.

### How does Omarchy distinguish between first-party and third-party plugins?

First-party plugins located in `$OMARCHY_PATH/shell/plugins` are implicitly enabled by the system. Third-party plugins installed in `~/.config/omarchy/plugins` must be explicitly added to the `plugins[]` array in [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json) or placed via the bar layout configuration. The `PluginRegistry.setEnabled()` method handles validation and writes the appropriate configuration entries.

### Can I programmatically move bar widgets without editing JSON manually?

Yes. Use the `putBarWidget` or `moveBarWidget` IPC commands via the `omarchy` CLI. For example, `omarchy launch shell putBarWidget "widget.id" '{"section":"left"}'` invokes the registry to update `shell.json.bar.layout` and triggers an immediate bar rebuild through `onShellConfigChanged`.

### How do panels receive data when summoned via IPC?

When `shell.summon(id, payload)` is called, the payload parameter passes through to the panel loader. If the QML component is still loading, the data queues in `pendingPayloads` until the component finishes instantiation and exposes its `open()` method, ensuring reliable data delivery even for slow-loading plugins.