How to Declare Custom Bar Modules Inline in Omarchy's shell.json
Yes, you can declare custom bar modules inline in Omarchy's shell.json by adding entries with type: "command" or type: "qml" to the bar.layout sections, which the BarModel.js parses and renders at runtime without requiring separate plugin registration.
Omarchy is an open-source desktop environment developed by Basecamp that uses a JSON-driven configuration system for its shell components. You can extend the top bar with custom widgets by declaring them inline in your shell.json file, eliminating the need to create full plugin packages for simple utilities.
Understanding the bar.layout Configuration Schema
The bar configuration lives under the bar: subtree in ~/.config/omarchy/shell.json (or the bundled default at config/omarchy/shell.json). The bar.layout object contains three sections—left, center, and right—each accepting an array of module definitions.
According to the Omarchy source code, when shell.qml loads the canonical configuration, it passes the parsed JSON object directly to the bar QML component. The shell/plugins/bar/BarModel.js file inspects each entry's type field to determine whether to instantiate a built-in widget or a custom module.
Types of Inline Custom Modules
Omarchy recognizes two primary types for inline declaration, plus a settings override pattern for existing widgets.
Command-Based Widgets (type: "command")
Use this pattern for simple scripts that output text. The BarModel.js creates a customCommandModuleComponent that spawns the specified process at the configured interval and displays its stdout.
{
"id": "custom.cpu",
"type": "command",
"exec": "bash -c \"printf 'CPU %s' \\$(grep -c '^processor' /proc/cpuinfo)\"",
"interval": 30,
"label": "CPU"
}
type: "command"tells the bar to spawn a processexeccontains the command line (wrap inbash -cfor complex scripts)intervalspecifies the refresh rate in secondslabelis optional; omit it to display the command's raw output
QML-Based Widgets (type: "qml")
For custom visual elements, specify a path to a QML file. The model resolves the path via customModulePath() and loads it through the customRoot component in Bar.qml.
{
"id": "custom.clock",
"type": "qml",
"source": "~/.config/omarchy/custom-clock.qml",
"label": "Clock"
}
type: "qml"signals the bar to load a QML componentsourceaccepts absolute paths or~-expanded paths to your home directory- The referenced QML file can contain any visual element, such as rotating logos or custom graphics
Patching Built-in Widgets with Settings
You can modify existing widgets without fully redefining them by specifying their id and a settings object. The BarModel.js merges these settings into the running widget without rebuilding the entire bar.
{
"id": "omarchy.clock",
"settings": {
"format": "15:04",
"showSeconds": false
}
}
This approach updates the configuration while preserving the widget's core functionality.
Runtime Processing and Hot-Reload
The inline declaration system relies on specific components in the Omarchy codebase:
shell/plugins/bar/BarModel.jsimplementscustomModuleSafeName(),customModuleType(), andcustomModulePath()to validate names, determine module types, and resolve source pathsshell/plugins/bar/Bar.qmlinstantiates either standard widgets or custom components based on the entry'stypefieldshell/shell.qmlhandles the initial JSON parsing and enables configuration hot-reloading
When you save changes to shell.json, run omarchy reloadConfig (or wait for auto-reload), and the bar rebuilds its layout using the updated inline definitions. No separate plugin registration is required, and the changes persist across restarts.
Summary
- Declare custom modules directly in
~/.config/omarchy/shell.jsonunderbar.layout.left,center, orright - Use
type: "command"for shell script output widgets with configurable refresh intervals - Use
type: "qml"for custom visual components stored as separate QML files - Override existing widgets by specifying their
idwith asettingsobject - Changes hot-reload automatically or via
omarchy reloadConfigwithout restarting the desktop environment
Frequently Asked Questions
Can I declare custom bar modules inline without creating a plugin package?
Yes. Omarchy's shell.json schema supports inline declaration for lightweight, one-off widgets. Simply add an entry with the appropriate type field to your bar.layout configuration. The BarModel.js processes these entries at runtime, so you do not need to create a full plugin package or register the module separately.
What programming languages can I use for command-type modules?
You can use any programming language that executes in your shell environment. The exec field accepts standard shell commands, so you can write scripts in Bash, Python, Ruby, or any other language available in your $PATH. The bar captures stdout and displays it in the widget.
Where should I store custom QML files for bar modules?
Store custom QML files in ~/.config/omarchy/ or any location accessible via absolute path. The source field in your shell.json entry supports tilde expansion (~), so ~/.config/omarchy/custom-widget.qml resolves correctly to your home directory when the BarModel.js processes the customModulePath.
Do I need to restart Omarchy after editing shell.json?
No. The shell.qml component monitors the configuration file for changes and hot-reloads the bar layout automatically. You can also trigger an immediate reload by running omarchy reloadConfig from a terminal. The bar reconstructs itself using the updated inline module definitions without requiring a full desktop 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →