Understanding the Omarchy shell.json Structure: State Management Schema Explained

The Omarchy shell.json file is a versioned JSON configuration located at ~/.config/omarchy/shell.json that serves as the single source of truth for desktop state, containing a mandatory version field, a bar object with widget layouts, and a plugins array for enabled services.

The basecamp/omarchy repository uses this file to persist and hot-reload the desktop environment's configuration without restarting the shell. Understanding the Omarchy shell.json structure is essential for customizing the bar layout, enabling plugins, and managing widget-specific settings across sessions.

Top-Level Schema Overview

The root object in shell.json follows a strict schema validated at load time. According to the loading logic in shell/shell.qml, the file must contain these primary keys:

  • version: An integer specifying the schema version. The current default is 1.
  • bar: An object describing the panel configuration and widget arrangement.
  • plugins: An array of strings listing enabled plugin identifiers.

Additional top-level keys may appear for plugin-specific configuration, but the three fields above form the required foundation.

The Bar Configuration Object

The bar object controls the on-screen panel's appearance and widget placement. As defined in the bundled default at [config/omarchy/shell.json](https://github.com/basecamp/omarchy/blob/quattro/config/omarchy/shell.json), this object supports the following structure:

{
  "bar": {
    "id": "local.main-bar",
    "transparent": false,
    "layout": {
      "left": [],
      "center": [
        {"id": "omarchy.clock", "type": "qml", "settings": {}}
      ],
      "right": []
    }
  }
}

Bar Properties

  • id: Optional string identifier for the bar instance. Used for debugging and multi-monitor scenarios.
  • transparent: Boolean flag. When set to true, the bar background becomes transparent.
  • layout: Required object containing three arrays: left, center, and right. These arrays determine widget positioning across the horizontal axis.

Widget Entry Structure

Each element within the layout arrays represents a widget entry with a standardized schema enforced by [shell/plugins/bar/BarModel.js](https://github.com/basecamp/omarchy/blob/quattro/shell/plugins/bar/BarModel.js):

  • id: Required string matching the plugin module name (e.g., "omarchy.clock").
  • type: Required string set to either "command" for executable-based widgets or "qml" for native Qt Quick components.
  • settings: Optional object containing widget-specific configuration overrides.

The shell watches shell.json for filesystem changes and rebuilds the bar layout immediately when these arrays are modified.

Plugin Management and Arbitrary Keys

Beyond the bar object, the Omarchy shell.json structure supports dynamic plugin configuration through two mechanisms:

The Plugins Array The plugins field contains an array of enabled service identifiers:

{
  "plugins": ["omarchy.nightlight", "omarchy.media", "omarchy.battery"]
}

The shell/services/PluginRegistry.qml reads this array to determine which services to activate during initialization. A plugin is considered enabled when its ID appears in this list or elsewhere in the configuration.

Module-Specific Configuration Any top-level key matching a plugin ID can store arbitrary configuration for that module. For example:

{
  "omarchy.weather": {
    "location": "Paris",
    "units": "metric"
  }
}

These entries merge with default settings at runtime, allowing per-plugin state persistence without modifying the plugin's source code.

Validation and Fallback Behavior

The shell implements robust validation logic in shell/shell.qml to handle malformed or missing configurations:

  1. Primary Load: Attempts to read ~/.config/omarchy/shell.json from the user's home directory.
  2. Fallback: If the user file is missing, unreadable, or contains invalid JSON, the shell falls back to the bundled [config/omarchy/shell.json](https://github.com/basecamp/omarchy/blob/quattro/config/omarchy/shell.json).
  3. Version Check: The shell validates the version field. If absent, it defaults to 1 and logs a warning to the console.
  4. Schema Enforcement: The test suite in [test/shell.d/config-test.sh](https://github.com/basecamp/omarchy/blob/quattro/test/shell.d/config-test.sh) asserts that layout.left, layout.center, and layout.right must be arrays, preventing runtime crashes from malformed widget definitions.

Practical Configuration Examples

Reading the current center widgets

jq '.bar.layout.center[].id' ~/.config/omarchy/shell.json

Adding a volume widget to the right side

jq '.bar.layout.right += [{"id":"omarchy.volume","type":"qml","settings":{"step":5}}]' \
  ~/.config/omarchy/shell.json > tmp.json && mv tmp.json ~/.config/omarchy/shell.json

Enabling the nightlight plugin

jq '.plugins += ["omarchy.nightlight"]' \
  ~/.config/omarchy/shell.json > tmp.json && mv tmp.json ~/.config/omarchy/shell.json

Toggling bar transparency

jq '.bar.transparent = true' \
  ~/.config/omarchy/shell.json > tmp.json && mv tmp.json ~/.config/omarchy/shell.json

Changes take effect immediately without restarting the desktop environment because the file watcher detects modifications and triggers a layout refresh through [shell/plugins/bar/BarModel.js](https://github.com/basecamp/omarchy/blob/quattro/shell/plugins/bar/BarModel.js).

Summary

  • The Omarchy shell.json structure consists of a versioned root object with three mandatory sections: version, bar, and plugins.
  • The bar object contains layout arrays (left, center, right) that define widget positioning using entries with id, type, and optional settings fields.
  • The plugins array controls which services load at runtime, while arbitrary top-level keys enable plugin-specific configuration storage.
  • The shell validates the file on load and falls back to default configurations located in config/omarchy/shell.json if the user file is corrupted or missing.
  • All changes are hot-reloaded, allowing real-time customization of the desktop environment.

Frequently Asked Questions

Where does Omarchy store the shell.json file by default?

Omarchy searches for shell.json at ~/.config/omarchy/shell.json in the user's home directory. If this file does not exist or contains invalid JSON, the shell automatically falls back to the bundled default located at config/omarchy/shell.json within the installation directory. This fallback mechanism ensures the desktop remains functional even when user configuration is corrupted.

What happens if I omit the version field in shell.json?

If the version field is missing, the shell assumes version 1 and logs a console warning. While the desktop will continue to function using default schema assumptions, omitting this field may cause unexpected behavior if future Omarchy releases introduce breaking schema changes. The version field acts as a migration marker for configuration updates.

Can I add custom settings for plugins directly in shell.json?

Yes, you can add arbitrary configuration keys at the top level of shell.json using the plugin's ID as the key name. These settings automatically merge with the plugin's defaults at runtime. For example, adding an "omarchy.clock" object with a format setting overrides the default time display format without modifying the plugin source code.

How does Omarchy detect changes to shell.json?

The shell initializes a filesystem watcher on ~/.config/omarchy/shell.json during startup. When the file is modified, the watcher triggers a reload sequence in shell/shell.qml that re-parses the JSON and updates the bar layout, plugin states, and widget configurations in real-time without requiring a session restart.

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 →