How to Configure Omarchy Shell Plugin Settings: JSON Persistence and QML Integration

Omarchy shell plugin settings are configured through individual JSON files stored in $HOME/.local/state/omarchy/settings/, which the shell automatically injects into QML components via a settings property and persists through a built-in file-watching mechanism.

The Omarchy desktop environment utilizes a modular plugin architecture where each extension manages its own persistent configuration without explicit file I/O code. Understanding how Omarchy shell plugin settings are configured requires examining the interplay between JSON storage, QML property injection, and manifest declarations that define user interfaces.

Where Plugin Settings Are Stored

Omarchy stores each plugin’s configuration as a separate JSON file under the user’s local state directory. When the shell instantiates a plugin from the shell/plugins/ directory, it creates a settings object populated from:

$HOME/.local/state/omarchy/settings/<plugin-id>.json

For example, the weather panel loads its configuration from weather.json (referenced in shell/plugins/panels/weather/Panel.qml), while the notifications service uses notifications.json (handled in shell/plugins/notifications/Service.qml).

If the JSON file does not exist, the shell supplies an empty object {} to the plugin, which may then write default values on first run.

Injecting Settings into QML Components

The shell injects the loaded JSON object into each plugin’s QML component through a standardized property binding. Every plugin QML file that requires configuration exposes a property declaration:

// shell/plugins/panels/tailscale/Service.qml
property var settings: ({})  // Injected by omarchy-shell at load time

// Accessing values
var value = settings ? settings[name] : undefined

This pattern appears across the codebase, including in shell/plugins/bar/widgets/Tray.qml and shell/plugins/notifications/Service.qml. The shell binds the JSON representation to this settings property, enabling automatic synchronization between the file system and the QML runtime.

Persistence and Auto-Save Mechanism

Changes to the settings object are automatically persisted through a helper mechanism that watches the settingsFile. According to the shell/plugins/notifications/Service.qml implementation, the system uses a FileView component combined with a save timer:

// shell/plugins/notifications/Service.qml
readonly property string settingsPath: stateDir + "notifications.json"

FileView {
    id: settingsFile
    path: service.settingsPath          // Monitored for external changes
    onReloaded: {
        // Parse JSON → service.settings object
    }
}

When QML code modifies the settings property, a settingsSaveTimer schedules a debounced write operation that serializes the object back to the JSON file. This design allows plugins to treat settings as reactive variables while the shell handles serialization, file watching, and hot-reload when external edits occur.

Declaring Settings UIs in Plugin Manifests

Plugins expose configuration interfaces to users through manifest declarations. The manifest.json file can specify a "settingsForm" field that tells the shell which UI form to instantiate:

// shell/plugins/panels/weather/manifest.json
{
  "id": "omarchy.weather",
  "kinds": ["panel"],
  "entryPoints": { "Panel": "Panel.qml" },
  "settingsForm": "weatherSettings"
}

When this field is present, the shell creates a form dialog bound to the same settings object, allowing users to edit the underlying JSON through a friendly interface rather than manually modifying files.

Managing Bar Widget Settings

Bar widgets follow a specialized pattern for settings management. The shell/plugins/bar/Bar.qml container injects settings into each widget at load time. When a widget updates its configuration, the shell/plugins/bar/BarModel.js handles partial persistence through the setWidgetSettings function:

// shell/plugins/bar/BarModel.js
function setWidgetSettings(entry, newSettings) {
    // Merge changes into the entry's stored JSON
    var entryCopy = JSON.parse(JSON.stringify(entry));
    entryCopy.settings = newSettings;
    writeEntry(entryCopy);  // Writes only the changed settings portion
}

This approach allows individual bar widgets to modify their settings object (as seen in shell/plugins/bar/widgets/Tray.qml with settings.pinned), while the bar model ensures only the relevant widget’s settings are written back to the plugin’s JSON file.

Summary

  • Storage Location: Plugin settings persist as JSON files in $HOME/.local/state/omarchy/settings/<plugin-id>.json.
  • QML Access: Use property var settings: ({}) in QML files to receive the injected configuration object from the shell.
  • Auto-Persistence: The shell automatically saves changes to JSON via FileView monitoring and debounced timers implemented in notifications/Service.qml.
  • UI Declaration: Add a "settingsForm" field to manifest.json to expose configuration dialogs to users.
  • Widget Updates: Bar widgets utilize BarModel.js methods to persist individual setting changes without rewriting entire configuration files.

Frequently Asked Questions

Where are Omarchy shell plugin settings files located?

Omarchy stores plugin settings in the user’s local state directory at $HOME/.local/state/omarchy/settings/<plugin-id>.json. Each plugin maintains its own JSON file named after its identifier, such as weather.json or notifications.json. If a file is missing when the plugin loads, the shell initializes an empty settings object that the plugin can populate.

How do I access settings inside a plugin's QML code?

Declare a property var settings: ({}) in your QML file, as implemented in shell/plugins/panels/tailscale/Service.qml and shell/plugins/bar/widgets/Tray.qml. The Omarchy shell automatically binds the loaded JSON object to this property before the component initializes, allowing immediate access to values through standard JavaScript object notation like settings.pinned or settings.enabled.

What triggers settings to save automatically in Omarchy plugins?

The shell implements a reactive persistence layer using a FileView component and a settingsSaveTimer. When QML code modifies the settings property, the timer schedules a debounced write operation to serialize the object back to the JSON file. Conversely, when the underlying file changes on disk, the FileView emits a onReloaded signal that updates the live settings object, enabling hot-reload of configuration changes.

How do I add a settings UI to my Omarchy plugin?

Add a "settingsForm" key to your plugin’s manifest.json file, specifying the form identifier as shown in shell/plugins/panels/weather/manifest.json. The shell detects this declaration during plugin loading and generates a configuration dialog bound to the plugin’s settings object, allowing users to modify values without directly editing the JSON file.

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 →