# How to Develop Omarchy Plugins: A Complete Guide to Building Desktop Extensions

> Learn to develop Omarchy plugins by creating manifest files and QML entry points. This guide covers enabling extensions and using hot-reload for efficient desktop development.

- Repository: [37signals/omarchy](https://github.com/basecamp/omarchy)
- Tags: how-to-guide
- Published: 2026-08-23

---

**Developing Omarchy plugins requires creating a directory with a [`manifest.json`](https://github.com/basecamp/omarchy/blob/main/manifest.json) file and QML entry points inside `~/.config/omarchy/plugins/`, then enabling them via the CLI to leverage automatic hot-reload during development.**

Omarchy is a desktop environment built by Basecamp that runs as a single long-lived Quickshell process (`omarchy-shell`). Every visible element—from the top bar to system dialogs—is implemented as a plugin that the shell loads at startup. Whether you are extending the UI with a custom widget or building a background service, understanding how to develop Omarchy plugins allows you to customize your entire desktop experience using QML and JavaScript.

## Understanding Plugin Locations

Omarchy distinguishes between first-party and third-party plugins based solely on disk location. Both are automatically scanned when the shell starts.

**First-party plugins** bundled with Omarchy reside in the repository under `"$OMARCHY_PATH/shell/plugins/"`. These are maintained by the core team and include essential components like `omarchy.clock` and `omarchy.network`.

**Third-party plugins** that you develop or install from external sources live in your home configuration directory:

```bash
~/.config/omarchy/plugins/

```

When the Quickshell process initializes, it scans both locations to discover available extensions.

## Creating the Plugin Manifest

Every Omarchy plugin requires a [`manifest.json`](https://github.com/basecamp/omarchy/blob/main/manifest.json) file at its root directory. This manifest declares the plugin's identity, capabilities, and entry points.

### Required Manifest Fields

According to the basecamp/omarchy source code documented in [`manual/32-shell-plugins.md`](https://github.com/basecamp/omarchy/blob/main/manual/32-shell-plugins.md), the manifest must include:

- **id**: A unique identifier for the plugin. Built-in plugins use the reserved `omarchy.` prefix (e.g., `omarchy.battery`), which is restricted to the core distribution. Your plugins should use a personal namespace like `username.pluginname`.
- **name**: Human-readable display name.
- **version**: Semantic version string.
- **kinds**: Array of plugin types such as `service`, `bar-widget`, `panel`, `osd`, or `fullscreen`.
- **entryPoints**: Map connecting each kind to its QML implementation file.

Example structure for a custom bar widget:

```json
{
  "id": "developer.weather",
  "name": "Weather Widget",
  "version": "1.0.0",
  "kinds": ["bar-widget"],
  "entryPoints": {
    "bar-widget": "WeatherBar.qml"
  }
}

```

### Validation Before Installation

Before enabling your plugin, validate the manifest against Omarchy's schema to catch configuration errors:

```bash
omarchy plugin validate ./developer.weather

```

This command checks for duplicate IDs, unsupported kinds, and valid entry point declarations without executing any plugin code.

## Implementing Plugin Kinds and UI Components

The `kinds` array in your manifest determines how Omarchy loads and displays your plugin. The full schema and IPC contract are documented in [`shell/README.md`](https://github.com/basecamp/omarchy/blob/main/shell/README.md), while the complete list of first-party plugin implementations is cataloged in [`shell/plugins/README.md`](https://github.com/basecamp/omarchy/blob/main/shell/plugins/README.md).

### Bar Widgets

Bar widgets appear in the top bar and may specify optional placement metadata:

- **defaultSection**: Determines initial placement (left, center, right).
- **allowMultiple**: Boolean flag permitting multiple instances on the same bar.

Place your QML files in the plugin directory and reference them in `entryPoints`. For example, a bar widget implementation lives at `~/.config/omarchy/plugins/developer.weather/WeatherBar.qml`.

### Services and Panels

Other plugin kinds include:

- **service**: Headless background processes (e.g., battery monitoring).
- **panel**: Expandable side panels or overlays.
- **osd**: On-screen display notifications.
- **fullscreen**: Lock screens or full-screen overlays.

Each kind maps to a specific QML file via the `entryPoints` object in [`manifest.json`](https://github.com/basecamp/omarchy/blob/main/manifest.json).

## Enabling and Configuring Plugins

Plugin state is managed through `~/.config/omarchy/shell.json`, which you modify indirectly via CLI commands rather than editing manually.

### Enabling Third-Party Plugins

To activate a plugin and optionally specify its bar section:

```bash

# Enable on the left section of the bar

omarchy plugin enable developer.weather --section left

# List all discovered plugins

omarchy plugin list

```

Third-party plugins are enabled by appearing in the configuration file (as a bar entry, a `plugins[]` element, or `bar.id`). First-party plugins are enabled by default and can only be turned off by listing them in a `disabledPlugins` array.

### Full-Bar Plugins

A **full-bar** plugin replaces the entire top bar and has no "off" state—enabling a different bar automatically replaces the current one.

## Installing from Git Repositories

To distribute or install third-party plugins, Omarchy supports a secure Git-based workflow that never executes arbitrary installation hooks:

```bash

# Add and immediately enable a plugin from a remote repository

omarchy plugin add https://github.com/acme/omarchy-weather.git --enable

```

The CLI performs the following operations:

1. Clones the repository to a temporary staging area.
2. Validates [`manifest.json`](https://github.com/basecamp/omarchy/blob/main/manifest.json) against the schema (checking for reserved IDs like `omarchy.*` and supported kinds).
3. Moves the verified plugin to `~/.config/omarchy/plugins/<id>/`.
4. Optionally enables the plugin if `--enable` is passed.

## Updating and Removing Plugins

Maintain your development environment with lifecycle commands:

```bash

# Update a specific plugin from its git remote

omarchy plugin update developer.weather

# Update all git-managed plugins (shows diff before applying)

omarchy plugin update

# Remove a plugin (disables first, then deletes or backups)

omarchy plugin remove developer.weather

```

The update command pulls the latest commit, displays a diff for review, and validates the new version before swapping files. The remove command moves hand-made plugins to a timestamped backup rather than deleting them immediately.

## Local Development Workflow

### Cloning Built-in Plugins

To modify existing behavior without editing core files, clone a built-in plugin into your user directory:

```bash
omarchy plugin clone omarchy.clock

```

This command:

- Copies the plugin from `"$OMARCHY_PATH/shell/plugins/omarchy.clock"` to `~/.config/omarchy/plugins/`.
- Prefixes the ID with your username (e.g., `dhh.clock` for user `dhh`).
- Preserves your previous bar placement and settings.
- Enables the cloned version immediately.

### Hot Reload During Development

Omarchy monitors `~/.config/omarchy/plugins/` for file changes. Save any QML or JavaScript file to trigger automatic hot-reload, allowing you to see UI changes instantly without restarting the shell.

For rapid iteration:

1. Create your plugin directory at `~/.config/omarchy/plugins/username.plugin/`.
2. Write [`manifest.json`](https://github.com/basecamp/omarchy/blob/main/manifest.json) with appropriate kinds and entry points.
3. Implement QML files (e.g., `Bar.qml` for bar widgets).
4. Validate with `omarchy plugin validate ./username.plugin`.
5. Enable with `omarchy plugin enable username.plugin`.
6. Edit files and observe changes immediately via hot-reload.

## Summary

- Omarchy plugins reside in `~/.config/omarchy/plugins/` for third-party development or `"$OMARCHY_PATH/shell/plugins/"` for first-party components.
- Every plugin requires a [`manifest.json`](https://github.com/basecamp/omarchy/blob/main/manifest.json) declaring a unique ID (avoid the reserved `omarchy.` prefix), version, kinds, and QML entry points.
- The CLI provides safe Git-based installation via `omarchy plugin add` without executing arbitrary code.
- Development is accelerated by hot-reload functionality that monitors file changes in the user plugins directory.
- Built-in plugins can be cloned for local modification using `omarchy plugin clone`, which automatically renames them with your username prefix.

## Frequently Asked Questions

### What programming languages are used to write Omarchy plugins?

Omarchy plugins are written using **QML** (Qt Meta Language) and **JavaScript**. The entry points declared in [`manifest.json`](https://github.com/basecamp/omarchy/blob/main/manifest.json) are QML files that define the user interface and behavior. System-level logic can be implemented through Qt's JavaScript integration or by interfacing with external processes.

### Can I distribute my plugin through the AUR or other package managers?

While the basecamp/omarchy source code supports Git-based installation via `omarchy plugin add`, you can distribute plugins through any mechanism that places files into `~/.config/omarchy/plugins/`. However, the native CLI tools in `bin/omarchy-plugin-*` expect Git remotes for update management. If installing manually through a package manager, ensure the [`manifest.json`](https://github.com/basecamp/omarchy/blob/main/manifest.json) is present at the plugin root and run `omarchy plugin validate` before enabling.

### Why does my plugin ID get rejected during validation?

Omarchy reserves the `omarchy.` namespace for first-party plugins distributed with the core system. If your manifest ID starts with `omarchy.`, validation will fail. Use a personal prefix like `githubusername.pluginname` or `com.company.pluginname`. Additionally, duplicate IDs across all discovered plugins (both first and third party) will cause validation errors.

### How do I debug a service plugin that has no visible UI?

Service plugins (declared with the `service` kind) run headless within the Quickshell process. Debug output appears in the shell's standard error stream. Launch `omarchy-shell` from a terminal to view console logs, or use QML's `console.log()` function within your service implementation. Since hot-reload applies to services as well, you can iterate on logic without restarting the desktop session.