# How Plugins Declare Themselves in Omarchy’s Quickshell: The Complete Manifest Guide

> Learn how plugins declare themselves in Omarchy's Quickshell by creating a manifest.json file. This guide details the validation and registration process for a seamless experience.

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

---

**Plugins declare themselves by placing a [`manifest.json`](https://github.com/omacom/omarchy/blob/main/manifest.json) file in a plugin directory under `$HOME/.config/omarchy/plugins` or the bundled `firstPartyDir`, which `shell/services/PluginRegistry.qml` validates and registers at startup.**

Omarchy’s Quickshell uses a declarative plugin system that loads third-party extensions through structured manifests. When Quickshell initializes, the registry scans designated directories, validates each [`manifest.json`](https://github.com/omacom/omarchy/blob/main/manifest.json) against a strict schema, and registers valid plugins for runtime component resolution. This guide explains exactly how plugins declare themselves according to the omacom/omarchy source code, including the required fields, validation logic, and enablement configuration.

## The Plugin Registry Architecture

Quickshell’s plugin discovery begins in `shell.qml`, which instantiates the `PluginRegistry` and passes two critical paths: the bundled `firstPartyDir` containing built-in plugins and the user-wide directory at `$HOME/.config/omarchy/plugins`. The registry walks each plugin directory, locates the [`manifest.json`](https://github.com/omacom/omarchy/blob/main/manifest.json) file, and validates it before registering the plugin for later lookup.

The registry stores validated manifests in an `installedPlugins` object and remembers each plugin’s source directory in `__sourceDir`. When components request a plugin entry point, the `entryPointUrl()` method (lines 93–107 in `shell/services/PluginRegistry.qml`) constructs a file URL by combining the source directory with the relative path defined in `entryPoints`, verifying that the resolved path remains within the plugin folder to prevent directory traversal.

## Manifest Schema and Required Fields

Every plugin must provide a [`manifest.json`](https://github.com/omacom/omarchy/blob/main/manifest.json) file conforming to schema version 1. The `PluginRegistry.qml` validation logic (lines 43–79) enforces strict requirements on field types and values to ensure runtime stability.

### Core Manifest Fields

The manifest must include these required fields:

- **`schemaVersion`** – Must be exactly `1`.
- **`id`** – Unique identifier string without slashes or `..` sequences (validated lines 59–63).
- **`name`** – Human-readable plugin title.
- **`version`** – Semver string indicating release version.
- **`kinds`** – Non-empty array of plugin types (`service`, `panel`, `bar`, `menu`, etc.).
- **`entryPoints`** – Object mapping each kind to a relative QML file path inside the plugin directory.

Optionally, plugins providing bar widgets may include a **`barWidget`** object specifying `defaultSection` as `"left"`, `"center"`, or `"right"` to indicate preferred placement.

### Validation Logic in PluginRegistry.qml

The registry performs comprehensive validation during the scanning phase:

1. **Schema verification** – Checks that the manifest is an object and `schemaVersion === 1` (lines 43–52).
2. **Field presence** – Ensures all required fields exist and that `id` contains no leading slashes or parent directory references (lines 59–63).
3. **Kinds validation** – Verifies `kinds` is a non-empty array (lines 64–66).
4. **Entry point safety** – Guarantees `entryPoints` is an object and every path is relative without `..` or leading `/` (lines 68–88).

## Defining Entry Points and Source Directories

The `entryPoints` object maps plugin kinds to QML files relative to the plugin’s root directory. For example, a service plugin points `"service"` to `"Service.qml"`, while a bar widget maps `"bar"` to `"BarWidget.qml"`.

When resolving components, `entryPointUrl()` double-checks that the constructed file URL stays within the plugin’s `__sourceDir`, preventing escape attempts via path manipulation. This ensures that plugins can only load QML files contained within their own directory tree.

## Bar Widget Configuration

Plugins supplying bar widgets may declare default positioning through the optional `barWidget` object. When present, this configuration specifies the `defaultSection` where the widget should appear if the user has not overridden placement in [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json).

```json
{
  "schemaVersion": 1,
  "id": "omarchy.clock",
  "name": "Clock",
  "version": "1.0.0",
  "kinds": ["bar"],
  "entryPoints": {
    "bar": "BarWidget.qml"
  },
  "barWidget": {
    "defaultSection": "center"
  }
}

```

## Enabling Plugins in Configuration

Plugin enablement depends on the `isEnabled()` method in `PluginRegistry.qml` (lines 10–38). First-party plugins (located in `firstPartyDir`) are treated as always enabled unless explicitly disabled. Third-party plugins from `$HOME/.config/omarchy/plugins` require explicit enablement in [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json) through the `plugins` array, `bar.id`, or `bar.layout.*` entries.

```json
{
  "plugins": [
    { "id": "omarchy.nightlight" },
    { "id": "omarchy.clock" }
  ]
}

```

When Quickshell reloads configuration, the registry checks these sections to determine which registered plugins should actively load their entry points.

## Summary

- Plugins declare themselves by placing a [`manifest.json`](https://github.com/omacom/omarchy/blob/main/manifest.json) in `$HOME/.config/omarchy/plugins` or the bundled `firstPartyDir`.
- `PluginRegistry.qml` validates manifests against schema version 1, checking required fields and safe paths at lines 43–79.
- Entry points must be relative QML files mapped in the `entryPoints` object; absolute paths and directory traversal are rejected.
- Optional `barWidget` configuration specifies default positioning for bar widgets as `left`, `center`, or `right`.
- First-party plugins enable automatically; third-party plugins require explicit listing in [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json).

## Frequently Asked Questions

### Where does Quickshell look for plugin manifests?

Quickshell scans two locations: the bundled `firstPartyDir` containing Omarchy’s built-in plugins and the user directory at `$HOME/.config/omarchy/plugins`. The `PluginRegistry` walks each directory at startup, reading [`manifest.json`](https://github.com/omacom/omarchy/blob/main/manifest.json) files from immediate subdirectories.

### What happens if a manifest fails validation?

The registry rejects invalid manifests during the initial scan. Specifically, `PluginRegistry.qml` (lines 43–79) validates `schemaVersion`, required field presence, safe `id` strings, non-empty `kinds` arrays, and relative `entryPoints` paths. Failed validations prevent registration, excluding the plugin from the `installedPlugins` object.

### Can entry point paths reference files outside the plugin directory?

No. The `entryPointUrl()` method (lines 93–107) constructs file URLs by combining the plugin’s `__sourceDir` with the relative path from `entryPoints`. It explicitly rejects paths containing `..` or leading slashes, ensuring resolved files remain within the plugin’s directory boundary.

### How do I disable a first-party plugin?

First-party plugins enable by default, but you can disable them by excluding their `id` from [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json) configuration sections or adding explicit disable entries where supported. The `isEnabled()` logic (lines 10–38) treats first-party plugins as enabled unless configuration explicitly overrides this behavior.