Omahub
← All plugins
I

Stack

by Ian Swope

Fold a run of bar widgets into one icon that opens them again on click, so a bar full of plugins stays a bar you can read.

Security review

No obvious issues detected

Deterministic scan — not a security guarantee

None
Risk level
None
Analyzed commit
ed9cc47
Scanned
1 week ago

No potentially dangerous behavior detected in the analyzed commit.

Automated analysis only — not a security guarantee.

AI advisory review

No obvious issues detected

Language-model assessment · ~deepseek/deepseek-v4-flash-latest — advisory only

None
AI risk level
None
Recommendation
install
Model
~deepseek/deepseek-v4-flash-latest
Analyzed commit
ed9cc47
Reviewed
1 week ago

The plugin is a benign UI utility that folds bar widgets behind an icon, reading configuration and shell files without writing or executing anything destructive. The deterministic scan found no issues, and the code is straightforward, well-commented, and includes tests. No malicious behavior, obfuscation, or hidden persistence was found.

How this check works

This review combines the deterministic scan (the rule-based results above) with an independent look at the plugin's code by a language model. The model reads a trimmed sample of the repository's files, the manifest, and the README, then gives a plain-language risk level and a recommendation: install (no notable danger), review (look closer first), or avoid (clearly dangerous).

It runs on the same analyzed commit as the deterministic scan and is strictly advisory — it is not a security guarantee and never blocks a plugin by itself. A human moderator still reviews plugins before they are listed.

AI advisory only — automated analysis, not a security guarantee.

Install
$ omarchy plugin add https://github.com/ianswope/omarchy-stack --enable
Appearance #bar #quickshell

Stack

Fold a run of bar widgets into one icon that opens them again on click, so a bar full of plugins stays a bar you can read.

Folded, a stack is one icon and a count. Click it and the widgets it holds appear on the bar, in order, behaving exactly as they would have on their own — same components, same settings, same panels. Click again and they go away.

Why it works at all

Omarchy's bar builds every widget from a registry of id → Component, and injects exactly three properties into each one: bar, moduleName, and settings. That is the whole contract. A stack reads the same registry, builds from the same components, and injects the same three properties, so a widget inside a stack is not a copy or a proxy of the real one — it is the real one, mounted somewhere else.

Reaching that registry takes one detour. An installed plugin is not handed the bar itself but a facade of presentation state and scoped callbacks, and there is no registry on it. The shell does hand a plugin the registry — into a plugin's service entry point — so this plugin declares one, Service.qml, whose entire job is to hold the barWidgetRegistry the shell injects into it. The panel reads it back with bar.shell.serviceFor(), which a plugin may call for its own id and no other. Nothing else in the plugin is a service: no timers, no state, no work.

If a future bar hands widgets a registry directly, the panel prefers that and the service is never consulted.

Configure

~/.config/omarchy/stacks.json:

{
  "stacks": [
    { "label": "System", "widgets": [
      { "id": "ianswope.keyring" },
      { "id": "ianswope.timers" },
      { "id": "ianswope.deploys" },
      { "id": "ianswope.snapshots" }
    ] },
    { "label": "Media", "widgets": [
      { "id": "ianswope.renders" },
      { "id": "ianswope.apple-music" },
      { "id": "ianswope.plex" }
    ] }
  ]
}

A bare stack object works too, as does a bare array of them — all three shapes are things a person plausibly writes. Each bar entry picks one with stackIndex. An entry may be a plain id string, or an object with its own settings, which are passed to the widget exactly as the bar would pass them:

{ "id": "ianswope.plex", "settings": { "refreshIntervalSec": 30 } }

The file is watched, so edits apply without restarting the shell.

The part that will catch you

A widget in a stack must still be named in shell.json, in the top-level plugins[] array.

Omarchy decides a plugin is enabled by whether its id appears anywhere in shell.json — a bar layout entry, or a plugins[] entry. Take a widget out of bar.layout.right and it is no longer enabled, so the shell never builds its component, so the registry never has it, so a stack has nothing to mount. The symptom is a stack that unfolds into nothing at all, with no error anywhere.

plugins[] is the answer: it marks a plugin enabled without placing it on the bar, which is exactly what a folded widget needs.

{
  "bar": { "layout": { "right": [
    { "id": "ianswope.stack", "stackIndex": 0 },
    { "id": "ianswope.stack", "stackIndex": 1 }
  ] } },
  "plugins": [
    { "id": "ianswope.keyring" },
    { "id": "ianswope.timers" },
    { "id": "ianswope.deploys" },
    { "id": "ianswope.snapshots" },
    { "id": "ianswope.renders" },
    { "id": "ianswope.apple-music" },
    { "id": "ianswope.plex" }
  ]
}

Leave a widget in both bar.layout and a stack and it gets built twice — two IPC handlers fighting over one target, two poll timers, two of whatever it does on a schedule. The stack notices that and says so in its tooltip, because nothing else will.

Settings

Setting Does
configPath Which file to read (default ~/.config/omarchy/stacks.json)
stackIndex Which stack in that file, 0 being the first
showCount Show how many widgets are folded away
startOpen Start unfolded when the shell loads

allowMultiple is on, so several stacks can sit on one bar, each with its own index.

What the icon tells you

The count is how many widgets are folded away; it disappears while unfolded, because they are right there. The icon turns urgent when something is wrong — a stack naming a plugin the shell cannot build, an entry that is not a plugin id, a widget that is also still on the bar, or no registry reaching the plugin at all. Hover for which.

Install

Requires Omarchy 4 ("Quattro", Quickshell bar).

mkdir -p ~/.config/omarchy/plugins
cp -r omarchy-stack ~/.config/omarchy/plugins/ianswope.stack

# 1. Write ~/.config/omarchy/stacks.json (above)
# 2. Add {"id": "ianswope.stack", "stackIndex": 0} to bar.layout.right
# 3. Move the folded widgets out of bar.layout and into plugins[]
omarchy-restart-shell

Remove

# Put the folded widgets back in bar.layout.right, remove the stack entries,
# and delete the plugins[] entries you added for them.
rm -rf ~/.config/omarchy/plugins/ianswope.stack
rm -f ~/.config/omarchy/stacks.json
omarchy-restart-shell

Nothing else is written anywhere. The stack reads shell.json to notice double-mounted widgets and never writes it — the bar owns that file.

Tests

node test/model-test.js

Covers the three config shapes, per-widget settings, the double-mount and not-installed checks, and what the tooltip says in each state.

Licence

MIT.