-
Notifications
You must be signed in to change notification settings - Fork 0
Publishing
Notes for listing this plugin on omarchyplugins.com, and what was done to meet the official develop and publish guidelines.
| Requirement | State |
|---|---|
manifest.json in the repo root |
yes |
Required fields, including license
|
all present |
Reverse-domain id, not omarchy.*
|
io.github.samy104.omarchy-spaces |
| Semantic versioning | 0.3.0 |
| Entry points are safe relative paths that exist | verified |
| No symlinks in the plugin folder | verified |
omarchy plugin validate |
passes |
qmllint -I $OMARCHY_PATH/shell |
zero errors |
omarchy plugin list --json reports id, kinds, enabled |
verified |
| Survives disable, re-enable, removal | verified |
| README with install, usage, config, removal, dependencies | yes |
| Public repo, LICENSE, preview image | yes |
No omarchy.clonedFrom key |
verified |
| Public repo, LICENSE, preview image | yes |
| Icon shipped at six theme sizes | assets/icon.png |
Exactly one manifest.json, at the root |
verified |
| GitHub topics | omarchy, omarchy-plugin, omarchy-shell |
The marketplace requires exactly one manifest.json, at the repository root:
/^(?:[^/]+\/)?manifest\.json$/i // root, or one directory deep
if (submission && (manifestPaths.length !== 1 || manifestPaths[0] !== "manifest.json"))
checkError("unsupported-repository-layout", ...)The first submission failed on exactly that. This repository shipped a second
plugin under workspaces/, one directory deep, so the pattern matched two
manifests and the rule rejected it.
The fix was not to bury the second manifest deeper until the regex stopped
matching. That would have satisfied the check while ignoring what it is for.
The two widgets are now one widget with two faces, chosen per placement by a
mode setting, with allowMultiple: true in the manifest. Place it twice and
you get what two plugins gave.
Omarchy's own Spacer and Indicators do the same thing, so this is the idiomatic shape rather than a workaround.
One thing that caught me out: omarchy plugin enable --section left moves an
existing placement rather than adding a second one. A second placement has to
be written into shell.json directly, which install.sh --replace-workspaces
does.
The guidelines require a bar widget's panel to forward opened, open(), and
close(). This plugin declares no panel kind, so that does not apply. The
switcher uses the Omarchy menu through a managed block in
~/.config/omarchy/extensions/omarchy-menu.jsonc, and configuration lives in a
separate GTK4 app rather than inside the shell process.
That is deliberate. A panel would have to build its own Wayland layer window, and the marketplace note is worth repeating: plugins run unsandboxed inside the long-running shell. Less code in that process is better.
Open the submission form with the repository link, a category, and tags. Automated validation runs against the current commit before a maintainer reviews it.
Add the omarchy-shell and omarchy-plugin topics to the GitHub repository so
it shows up under those topics as well.
The shell plugin is a long-lived process, so it never reads its config or state
file with cat. A marketplace security review flagged that, correctly: cat
follows symlinks, blocks forever on a FIFO, and streams a file of any size into
a collector.
Both reads now go through omarchy-spaces read-file, which opens with
O_NOFOLLOW and O_NONBLOCK, calls fstat on the same descriptor it will read
from rather than stat-ing the path a second time, and refuses anything that is
not a regular file owned by the caller within a byte limit. The limit is checked
while reading as well as before, since a file can grow between the stat and the
last read.
FileView on those two files is gone as well, for the same reason: it is a read
of a replaceable path by the long-lived process. Directory watches remain, used
only as a signal to re-read.
That costs one thing worth stating. A directory watch fires on an atomic rename, which is how the CLI and the configuration app both save, so those apply at once. An in-place hand edit changes the file without changing the directory and produces no event, so it is picked up on the service's existing tick instead, within about twenty seconds.
test/safe_read.test.py covers each refusal: symlink, FIFO, directory, device
node, oversized, and the boundary where a file exactly at the limit is still
read. The FIFO case runs under a timeout, because the failure mode being tested
is a hang rather than a wrong answer.
./test/run.sh
omarchy plugin validate ~/.config/omarchy/plugins/io.github.samy104.omarchy-spaces
/usr/lib/qt6/bin/qmllint -I /usr/share/omarchy/shell *.qml workspaces/*.qml
omarchy plugin list --json | grep samy104
./scripts/publish-wiki.shBump version in both manifests and in the README status line together.
Every CLI command, subcommand, and config key is checked against the docs before release. The check is mechanical rather than a read-through, since a reader skims and a script does not:
python3 - <<'CHECK'
import re, glob
cli = open("bin/omarchy-spaces").read()
docs = "".join(open(f).read() for f in glob.glob("docs/*.md")) + open("README.md").read()
cmds = set(re.findall(r'"([a-z-]+)":', re.search(r'COMMANDS = \{(.*?)\n\}', cli, re.S).group(1)))
print("undocumented:", sorted(c for c in cmds if c not in docs) or "none")
CHECKIt has caught two real gaps: the discover family and switchNotification.