Themes now drive typography the same way they drive colors: one [font] base-size in shell.toml is the rem root, and every Style.font.<token> (caption, bodySmall, body, subtitle, title, heading, display, displayLarge, iconSmall, icon, iconLarge) derives from it via a fixed multiplier. Themes can also pin individual tokens for stylistic emphasis. base-size is clamped 11..13 until row-height tokens exist. Bar dimensions move to the same singleton: [bar] size-horizontal / size-vertical replace the hardcoded 26/28 in Bar.qml, exposed as Style.bar.sizeHorizontal / sizeVertical. Style.qml also resolves the fontconfig 'monospace' alias via fc-match and exposes Style.font.resolvedFamily so panels can display the concrete family. Watches ~/.config/fontconfig/fonts.conf so it tracks 'omarchy font set <name>'. The qs.Ui kit (PillButton, Dropdown, Toggle, TextField, etc.) and every first-party plugin (bar widgets, settings, menu, clipboard, emoji, polkit, notifications, osd, image-picker, dev-gallery) now bind to Style.font.* instead of pixel literals. Only three deliberate display-scale outliers remain: the notification empty-state glyph and the weather flyout's hero temperature pair, all commented. Background plugin's applyTheme IPC fast-path also pushes shell.toml to Style so theme swaps update typography and bar size without waiting for inotify debounce. Dev gallery (omarchy dev ui-preview) now ships a Typography section that renders the full scale and theme tokens live, and its summon command is fixed (omarchy-shell-ipc -> omarchy-shell).
6.7 KiB
omarchy-shell
A single long-running Quickshell instance
that hosts the Omarchy desktop. The bar, panels, overlays, menus, and
services all run inside as plugins. IPC is the canonical way for CLIs
to talk to a running shell — omarchy-shell-ipc auto-starts it on
first call.
Plugin manifest
{
"schemaVersion": 1,
"id": "my.org.cool-clock",
"name": "Cool clock",
"version": "1.0.0",
"author": "You",
"description": "A clock that does cool things",
"kinds": ["bar-widget"],
"activation": "on-demand",
"entryPoints": { "barWidget": "Widget.qml" }
}
kinds (a manifest may declare more than one):
| Kind | What it is |
|---|---|
bar-widget |
Component the bar drops into a section |
panel |
Floating window (e.g. bar settings) |
overlay |
Fullscreen overlay (e.g. background picker) |
menu |
Summoned menu surface |
service |
Headless singleton, no UI |
activation is persistent (loaded at startup) or on-demand
(loaded by shell summon, unloaded by shell hide). On-demand
plugins can set keepLoaded: true to survive between summons.
Full schema: shell/services/PluginRegistry.qml.
Installing a third-party plugin
- Drop into
~/.config/omarchy/plugins/<id>/with amanifest.jsonplus the QML referenced fromentryPoints. omarchy-shell-ipc shell rescanPluginsomarchy-shell-ipc shell setPluginEnabled <id> true- Bar widgets also need adding to a section via bar settings.
IPC
The shell exposes a shell target plus extra targets registered by
individual plugins (bar, image-selector, …).
| Method | Effect |
|---|---|
ping |
health check |
summon <id> <payloadJson> |
load + open a plugin |
hide <id> |
close a previously-summoned |
toggle <id> <payloadJson> |
summon if closed, hide if open |
rescanPlugins |
re-walk plugin dirs |
setPluginEnabled <id> <"true"|…> |
flip enabled bit |
listPlugins |
JSON of every discovered plugin |
setPluginEnabled takes a string; only literal "true" enables.
shell.json
{
"version": 1,
"bar": {
"position": "top",
"transparent": false,
"centerAnchor": "calendar",
"fontFamily": "JetBrainsMono Nerd Font",
"layout": {
"left": [ { "id": "omarchy" } ],
"center": [ { "id": "calendar", "format": "HH:mm" } ],
"right": [ { "id": "audioPanel" } ]
}
},
"plugins": [
{ "id": "community.weather-extra" }
]
}
Rules:
- Every plugin instance is one entry —
bar.layout.<section>for bar widgets,plugins[]for everything else. - Settings are inline on the entry. No
config:sub-object, no merge layers. - Enabled ⇔ present.
allowMultiple: truein the manifest permits multiple instances.version: 1is required.
shell-defaults.json describes the fresh-install state. When no
user shell.json exists, defaults are used verbatim. Once the user
customizes, shell.json is canonical — there is no deep-merge.
Theme tokens
Themes ship colors in themes/<name>/colors.toml and surface roles +
sizing in themes/<name>/shell.toml. Defaults are generated from
default/themed/shell.toml.tpl; a theme may also drop a hand-written
shell.toml next to its colors.toml to override individual keys.
The shell exposes these tokens to QML via two singletons in
qs.Commons:
Color— palette (foreground,background,accent,urgent) and per-surface roles (Color.bar.*,Color.popups.*,Color.notifications.*,Color.menu.*,Color.imagePicker.*).Style— structural tokens (cornerRadius, focus affordances), the type scale (Style.font.*), and bar dimensions (Style.bar.sizeHorizontal/Style.bar.sizeVertical).
Typography
[font] base-size is the rem root for the scale. Every
Style.font.<token> derives from it via a fixed multiplier, so
bumping base-size rescales the whole shell proportionally:
| Token | Multiplier | Default |
|---|---|---|
Style.font.caption |
0.833 | 10 |
Style.font.bodySmall |
0.917 | 11 |
Style.font.body |
1.0 | 12 |
Style.font.subtitle |
1.083 | 13 |
Style.font.title |
1.167 | 14 |
Style.font.heading |
1.333 | 16 |
Style.font.display |
2.0 | 24 |
Style.font.displayLarge |
2.333 | 28 |
Style.font.iconSmall |
bodySmall | 11 |
Style.font.icon |
title | 14 |
Style.font.iconLarge |
1.5 | 18 |
A theme can either scale everything by tweaking base-size:
[font]
base-size = 13 # roomier
…or pin individual tokens for stylistic emphasis without affecting the rest of the scale:
[font]
base-size = 12
heading = 20
display-large = 36
Recognized override keys: base-size, caption, body-small,
body, subtitle, title, heading, display, display-large,
icon-small, icon, icon-large.
base-size is clamped to 11..13 because row heights and the bar
cross-axis size are fixed; per-token overrides aren't clamped. The
shell font family is the fontconfig monospace alias — themes don't
set it, the user does via omarchy font set <name>.
Bar size
[bar] size-horizontal / size-vertical set the cross-axis dimension
of top/bottom and left/right bars respectively (in px):
[bar]
size-horizontal = 26 # top/bottom bar height
size-vertical = 28 # left/right bar width
Custom bar modules
If a full plugin is overkill, declare a one-off module inline in
bar.layout.<section>:
{ "id": "vpn", "type": "command", "exec": "~/.config/omarchy/bar/scripts/vpn-status",
"interval": 5, "tooltip": "VPN", "onClick": "nm-connection-editor" }
Output is plain text or Waybar-style JSON ({ "text": ..., "tooltip": ..., "class": ... }).
For a custom QML widget:
{ "id": "gpu", "type": "qml" }
Then ~/.config/omarchy/bar/modules/gpu.qml (or set source to point
elsewhere). The module is an Item and receives bar, moduleName,
settings properties. bar exposes foreground / background /
urgent / fontFamily / position / vertical / barSize, plus
run(cmd), shellQuote(v), showTooltip(t, s) / hideTooltip(t),
requestPopout(o) / releasePopout(o).