omakit 0.1.9 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,51 +2,13 @@
2
2
  <img src="docs/media/banner.gif" alt="omakit" width="440">
3
3
  </p>
4
4
 
5
- [![Built for Omarchy: App](https://raw.githubusercontent.com/tcballard/omarchy-badges/75975e5b5bf75e7ede3764bcd2950046f7abfe2c/badges/v1/omarchy-app.svg)](https://github.com/tcballard/omarchy-badges)
5
+ The safe place to find out: everything knowable about an Omarchy Quattro plugin submission before you post it, on your own machine. Agent-first, read-only against the marketplace, posts nothing, zero dependencies.
6
6
 
7
- **Everything knowable about an Omarchy Quattro plugin submission, checked
8
- before you post it:** the tree, the manifest, the form, the commit, and the
9
- marketplace's own security baseline with its outcome reported as it is. A
10
- submission is judged at one exact commit and drifts from it the moment you
11
- push; `watch` says when that has happened. All of it runs on your own machine
12
- and publishes nothing: no issue, no comment, no label, nobody's attention spent
13
- until you choose to.
7
+ [![Built for Omarchy: App](https://raw.githubusercontent.com/tcballard/omarchy-badges/75975e5b5bf75e7ede3764bcd2950046f7abfe2c/badges/v1/omarchy-app.svg)](https://github.com/tcballard/omarchy-badges) [![npm version](https://img.shields.io/npm/v/omakit)](https://www.npmjs.com/package/omakit) [![CI status](https://img.shields.io/github/actions/workflow/status/mtolhuys/omakit/ci.yml?branch=main)](https://github.com/mtolhuys/omakit/actions/workflows/ci.yml) [![Socket](https://socket.dev/api/badge/npm/package/omakit)](https://socket.dev/npm/package/omakit)
14
8
 
15
- ![omakit submit refusing a plugin with no license, a README that never says how to uninstall, and a reserved plugin id](docs/media/submit.gif)
16
-
17
- The plugin above is refused for three things the marketplace itself refuses,
18
- and warned about a fourth: it ships instruction files an agent will read once
19
- installed. **103 marketplace issues mention exactly that, and no automated check
20
- reports it, so today an author finds out from a human review round.** It is a
21
- warning and not a refusal, because the marketplace does list plugins that ship
22
- them: 6 of 34 inspected do, at the commit that was listed.
23
-
24
- ```bash
25
- omakit submit <plugin-repo> --category Widgets --tags bar,quickshell
26
- ```
27
-
28
- Fifteen checks, each naming its source and, when it fails, the measured reason it
29
- exists. A blocking failure produces no submission body at all, because a refusal
30
- that still hands you the body is only a suggestion.
31
-
32
- ## Why it exists
33
-
34
- Four numbers, all measured on public marketplace data on 2026-09-12. Method,
35
- limits and the rest of the figures: [docs/MEASUREMENTS.md](docs/MEASUREMENTS.md).
36
-
37
- | Measured | Consequence |
38
- | --- | --- |
39
- | 39 submissions fell out on the title prefix alone, and 11 more are malformed in the body, one by a single word | the format is generated from the pinned form and judged by the marketplace's own parser |
40
- | 1,215 of the 2,916 listings with a recorded baseline needed a human to look, because of a capability | the official baseline runs locally on the exact commit first, and names the capability |
41
- | 103 issues mention agent-control files, which no automated check reports | submit names every one with its remedy, before a reviewer has to |
42
- | 73% of parked submissions have a HEAD the marketplace never saw; 46% of the maintainer's own revalidation requests never produced one | a validation watch that names the one action which re-runs validation |
43
-
44
- It does not claim to unblock the maintainer. His review writing barely repeats,
45
- his median time from submission to publication is hours, and the queue waiting on
46
- him is a median half a day old. The honest size of what this saves him is the
47
- staleness paragraph he has written by hand on 358 issues, roughly 5.5% of his
48
- review writing. The rest of the benefit is the submitter's.
49
- [docs/MARKETPLACE.md](docs/MARKETPLACE.md) states that in full.
9
+ `omakit` is a zero-dependency Node CLI that checks an Omarchy Quattro plugin submission on your machine.
10
+ It is for a coding agent or a person submitting a plugin.
11
+ It never posts to the marketplace or writes into a plugin tree.
50
12
 
51
13
  ## Install
52
14
 
@@ -55,203 +17,65 @@ npm install --global omakit
55
17
  omakit setup
56
18
  ```
57
19
 
58
- If `omakit` is not found afterwards, npm's global `bin` is not on your PATH
59
- (measured: an npm global prefix under `~/.local/share` whose `bin` no shell
60
- searched). Run `"$(npm prefix --global)/bin/omakit" setup` once: it prints the
61
- one line that puts that directory on PATH for the shell in `$SHELL`, and the
62
- rc file to keep it in; `omakit doctor` reports the same as `omakit.path`.
63
- Nothing writes to your rc file.
20
+ See [docs/INSTALL.md](docs/INSTALL.md) for the clone route, PATH, requirements and upgrading.
64
21
 
65
- Or read what you run:
22
+ ## Commands
23
+
24
+ | Command | What it does |
25
+ | --- | --- |
26
+ | [`omakit setup`](docs/COMMANDS.md) | The environment, the pin, tab completion, and what to try first. |
27
+ | [`omakit submit <plugin-repo>`](docs/SUBMIT.md) | Every check, the issue title and body; asks for a category and tags at a terminal. |
28
+ | [`omakit watch <issue-url>`](docs/VALIDATION_WATCH.md) | The commit the marketplace validated, against the plugin's current HEAD. |
29
+ | [`omakit verify <plugin-repo>`](docs/COMMANDS.md) | The official security baseline over the local transport; `--json` for the document. |
30
+ | [`omakit parity`](docs/COMMANDS.md) | The baseline over GitHub versus the local transport, on real listings; writes the evidence. |
31
+ | [`omakit weigh <plugin>`](docs/WEIGH.md) | What a plugin weighs on the shell, measured by restarting it without and with the plugin; asks first. |
32
+ | [`omakit doctor`](docs/COMMANDS.md) | What is installed, what is pinned, and what has moved. |
33
+ | [`omakit pin`](docs/COMMANDS.md) | What setup does for the pin, on its own. |
34
+ | [`omakit upgrade`](docs/COMMANDS.md) | Updates omakit through its own installer: npm, or a fast-forward. |
35
+ | [`omakit help --agent`](docs/COMMANDS.md) | The operating instructions, for the agent running this. |
36
+
37
+ ### `submit`
66
38
 
67
39
  ```bash
68
- git clone --depth 1 https://github.com/mtolhuys/omakit ~/.local/share/omakit
69
- ln -s ~/.local/share/omakit/bin/omakit ~/.local/bin/omakit
70
- omakit setup
40
+ omakit submit <plugin-repo> --category Widgets --tags bar,quickshell
71
41
  ```
72
42
 
73
- | Needs | Why |
74
- | --- | --- |
75
- | Node 22 or newer | the tool is plain ESM with no dependencies and no build step. A stock Omarchy has Node and npm through `mise`, along with `git`, `gh` and `ttfx` |
76
- | `git` | the pin, and reading a subject's tree at an exact commit |
77
- | network, once | `omakit pin`. After that, `submit` and `verify` on a local repository need none at all |
78
- | 15 MB on disk | the pinned checkout, in `$XDG_CACHE_HOME/omakit/marketplace`, or `~/.cache/omakit/marketplace` |
43
+ It decides whether the plugin is ready, refused, or already listed; [103 issues mention agent-control files that no automated check reports](docs/MEASUREMENTS.md).
79
44
 
80
- `omakit upgrade` updates either install through the installer that made it:
81
- `npm` for the package, at the exact version the registry names, and a
82
- fast-forward for a clone. `omakit doctor` says when a newer version is
83
- published. Nothing in omakit fetches and runs its own replacement, and
84
- `omarchy-mise-install npm:omakit` would, so it is not the way in.
45
+ ![omakit submit refusing a plugin with no license, a README that never says how to uninstall, and a reserved plugin id](docs/media/submit.gif)
85
46
 
86
- ## Watch
47
+ Read more: [docs/SUBMIT.md](docs/SUBMIT.md).
87
48
 
88
- ![omakit watch reporting that a validated commit has fallen behind](docs/media/watch.gif)
49
+ ### `watch`
89
50
 
90
51
  ```bash
91
52
  omakit watch <submission-issue-url>
92
53
  ```
93
54
 
94
- That submission passed validation and passed the security baseline with zero
95
- findings. It is stuck because the marketplace validated one exact commit, and
96
- the only action that makes it validate a newer one is editing the issue body. Pushing the fix does
97
- nothing. Commenting "fixed in `abc123`" does nothing. **73% of the 464
98
- submissions parked in their author's court have a default-branch HEAD the
99
- marketplace never saw.**
55
+ It decides whether the marketplace validated the plugin's current commit; [73% of parked submissions have a HEAD the marketplace never saw](docs/MEASUREMENTS.md).
100
56
 
101
- ## Commands
57
+ ![omakit watch reporting that a validated commit has fallen behind](docs/media/watch.gif)
58
+
59
+ Read more: [docs/VALIDATION_WATCH.md](docs/VALIDATION_WATCH.md).
102
60
 
103
- Agent-first: the expected user is a coding agent submitting a plugin on an
104
- owner's behalf. Zero dependencies, plain ESM, one entry point, no build step.
61
+ ### `weigh`
105
62
 
106
63
  ```bash
107
- omakit setup # the environment, the pin, tab completion, and what to try first
108
- omakit submit <plugin-repo> # every check, the issue title and body; asks for a category and tags at a terminal
109
- omakit watch <issue-url> # the commit the marketplace validated, against the plugin's current HEAD
110
- omakit verify <plugin-repo> # the official security baseline over the local transport; --json for the document
111
- omakit parity # the baseline over GitHub versus the local transport, on real listings; writes the evidence
112
- omakit doctor # what is installed, what is pinned, and what has moved
113
- omakit pin # what setup does for the pin, on its own
114
- omakit upgrade # updates omakit through its own installer: npm, or a fast-forward
115
- omakit help --agent # the operating instructions, for the agent running this
64
+ omakit weigh <plugin-id-or-dir>
116
65
  ```
117
66
 
118
- ![omakit setup checking the environment and fetching the pinned checkout](docs/media/setup.gif)
119
-
120
- `omakit setup` checks the environment, fetches the marketplace checkout that
121
- every rule is read from, installs tab completion for the shell you run it from
122
- (bash, zsh or fish, read from `$SHELL`), and tells you what to try first. It is
123
- idempotent. The fetch takes about 2 seconds and 15 MB, because it takes only the
124
- seven files omakit reads out of that repository rather than the 325 MB it is at
125
- that commit. The completion script knows the subcommands and their flags,
126
- completes a directory for `<target>`, and offers the categories and tags the
127
- pin's submission form actually has.
128
-
129
- `omakit verify` prints the official baseline result alone, with no Omakit
130
- check around it: the subject, the pin, the transport and what the local
131
- adapter assumes, then the marketplace's own outcome, each finding as a block
132
- with its rule id, whether it blocks publication under the pinned policy, the
133
- file and line, and the official text verbatim, then the marketplace's own
134
- statement. `--json` prints the document itself, unchanged from earlier
135
- releases, and `--out <file>` writes it; agents and the skills use those.
136
-
137
- `omakit submit` reads the marketplace's registry first, and a run has three
138
- outcomes. `READY`, exit 0: every blocking check passed and the title and body
139
- follow. `REFUSED`, exit 1: a blocking check failed and no body is produced.
140
- `LISTED`, exit 0: the plugin is already listed by its own repository (the
141
- manifest id is in the catalog, and the listing's repository is the subject's
142
- declared `origin`, compared as owner and name), so the submission form is not
143
- the route. Nothing is wrong and nothing was refused: `identity.available`
144
- passes with the listing's record (since when, which commit, verified or not),
145
- the five checks that exist only for the body are omitted, nothing is asked,
146
- and the closing block names the commit the marketplace lists, the local
147
- commit, whether they are the same, and the marketplace's verification form
148
- with the choice that lists a newer commit, read from the pin's
149
- `verify-plugin.yml`. Measured on 0.1.6: this state printed `FAIL
150
- identity.available`, `REFUSED`, and "Fix it, then run submit again" under a
151
- remedy that said there was nothing to submit. An id taken by another
152
- repository, a retired id or a reserved one is still refused. In `--json`, the
153
- outcome is `outcome: "ready" | "refused" | "listed"`, `ready` stays a boolean
154
- that is true for the first only, and a listed run carries a `listing` object.
155
-
156
- An unlisted plugin needs a category and tags, and they are an editorial
157
- choice nobody else can make: at a terminal it asks, once each, with the form's
158
- own lists numbered and the marketplace's own default for the manifest's kinds
159
- offered where it is on the list; in a pipe, from an agent, or with `--json` it
160
- is the usage error with the same lists, exit 2. A listed plugin is asked for
161
- neither. A `READY` or `REFUSED` report ends with the command line that repeats
162
- the run without asking, and `--json` carries it as `reproduce`.
163
-
164
- There is nothing to authenticate. If you have `gh auth login` done, omakit
165
- reads that credential for GET requests and stores nothing; a token in
166
- `GH_TOKEN` or `GITHUB_TOKEN` reaches it the same way, because `gh` honours
167
- those itself. Without either, `watch` and `parity` share GitHub's
168
- 60-requests-an-hour unauthenticated allowance; `submit` reads two things
169
- online, the subject's default-branch HEAD and the marketplace's current
170
- registry, and `--offline` turns both off; `verify` on a local repository does
171
- not touch the network at all (a `<url>@<sha>` target is fetched once, over
172
- git, into the cache). omakit reads no environment variable of its own, and
173
- `omakit doctor` names the credential source it found, or that it found none.
174
-
175
- Every colour omakit prints is an ANSI palette index, so your Omarchy theme
176
- decides what it looks like, and nothing is said by colour alone. What the
177
- terminal shows and why is [docs/TUI.md](docs/TUI.md); which index each role
178
- gets, measured over all 32 installed themes, is
179
- [docs/PALETTE.md](docs/PALETTE.md).
180
-
181
- ## What it is doing
182
-
183
- Nothing about the submission format is written down in this repository. The
184
- title prefix, the six form headings in order, the nine categories, the thirteen
185
- tags and the exact text of the five checklist items are all read from
186
- `.github/ISSUE_TEMPLATE/submit-plugin.yml` in a marketplace checkout pinned to an
187
- exact commit. The rendered body is then handed to the marketplace's own
188
- `parseCurrentSubmission` from that same commit. If it accepts the body here, it
189
- accepts it there. The one exception is data, not rules: the registry and the
190
- catalog that say which ids and repositories are already listed are read from
191
- the marketplace's current HEAD when the network is there, because the pin's
192
- copy is stale within hours (4,201 of 4,293 commits in 30 days touched only
193
- `registry.json`), and from the pin with `--offline`.
67
+ It measures what a plugin weighs on the shell, CPU and child processes, against a baseline taken the same minute; [in the lab, a 180 ms timer fixture measured 2.73% CPU above a 0.13% floor](docs/MEASUREMENTS.md).
194
68
 
195
- This is why the tool is Node: the marketplace's scanner, form parser and
196
- catalog builder are Node modules, and omakit runs them verbatim from the
197
- pinned commit instead of reimplementing their rules, where a different
198
- language would mean a copy that can drift.
199
-
200
- The security baseline is the marketplace's own code, imported unmodified and run
201
- over a local snapshot with no network. Omakit adds no rule, renames no outcome,
202
- and never restates the result as a safety claim: the baseline does no data-flow
203
- analysis and is not a security review, and the output says so in the
204
- marketplace's own words.
205
-
206
- Every check is labelled. `[marketplace-pin]` is the marketplace's rule, read from
207
- the pin. `[omakit]` is this project's own check, derived from public issue data.
208
- Those are not marketplace policy and do not claim to be.
209
-
210
- ## Updating
211
-
212
- Two different things could mean "upgrade" here, and only one of them may ever
213
- move on its own. That distinction is now enforced rather than argued.
214
-
215
- **The tool:**
216
-
217
- ```bash
218
- omakit upgrade # the npm package, or a clone: through its own installer
219
- omakit upgrade --dry-run
69
+ ```text
70
+ Weighs no CPU above the floor (0.13%) and runs 2 child processes using 8.2 MB and 0.1% CPU, on Omarchy 4.0.0.alpha, measured with omakit weigh on 2026-09-14
220
71
  ```
221
72
 
222
- It is not a self-updater of the kind this repository warns other people
223
- about: it never fetches and runs its own replacement. On an npm install it asks
224
- the registry for the newest version and, if that is newer, runs the `npm` on
225
- PATH with frozen arguments (`npm install --global --ignore-scripts omakit@<that
226
- version>`, never `@latest`, never with sudo), and it refuses when the npm on
227
- PATH is not the one that installed it. On a clone it fast-forwards from the
228
- remote you cloned it from, and refuses a dirty tree, a detached HEAD, a remote
229
- that is not this repository, and anything that is not a fast-forward. In every
230
- refusal it names what to run yourself. `git -C ~/.local/share/omakit pull`
231
- still works on a clone and does the same thing.
73
+ It restarts your shell and asks first. Memory is a shell fact; CPU and child processes are the weight.
232
74
 
233
- **The pin** does not move by itself, ever, and `omakit upgrade` does not move it
234
- either: a test asserts that its source does not so much as mention the pin or
235
- the cache. Bumping it changes where the submission contract and the baseline
236
- policy are read from, and the procedure in
237
- [docs/UPSTREAM_CONTRACT.md](docs/UPSTREAM_CONTRACT.md) ends in re-proving
238
- transport parity and committing the evidence. `omakit doctor` tells you when the
239
- pin is behind in something omakit reads from it, names which paths changed,
240
- and then leaves it alone: `registry.json` and `site/catalog.json` moving is
241
- fine, because those are read live from HEAD (about 140 commits a day touch
242
- only `registry.json`, so "behind" alone would be true of every run); the
243
- marketplace's code or forms moving is a note, and what you can do about it
244
- is run `omakit upgrade`, since a newer omakit may already carry the new pin,
245
- and otherwise open an issue naming the paths. That the
246
- pin can go stale unnoticed is the same defect class `omakit watch` reports, so it
247
- would be poor form to hide it here.
75
+ Read more: [docs/WEIGH.md](docs/WEIGH.md).
248
76
 
249
77
  ## Evidence, not claims
250
78
 
251
- ```bash
252
- npm test # node --test, no dependencies; green from `git archive` too
253
- ```
254
-
255
79
  | Claim | Proof |
256
80
  | --- | --- |
257
81
  | The local transport produces the marketplace's own result | 30 of 30 identical, [docs/evidence/parity/](docs/evidence/parity/) |
@@ -259,17 +83,20 @@ npm test # node --test, no dependencies; green from `git archive` too
259
83
  | The generated body is well formed | the marketplace's own parser, `tests/unit/issue.test.mjs` |
260
84
  | Nothing writes to the marketplace | `tests/unit/read-only.test.mjs`, over every source file |
261
85
  | No agent-control file can reach a plugin | `tests/unit/self-containment.test.mjs` |
86
+ | `weigh` restores `shell.json` on every exit path, and runs a frozen list of Omarchy commands | `tests/unit/weigh.test.mjs` against a fake `/proc` and stub commands, `tests/unit/read-only.test.mjs` |
262
87
  | The GIFs above are real output | captures and renderer in [docs/media/](docs/media/) |
263
88
 
264
- Committed evidence records a digest of each side rather than the results
265
- themselves: findings about a specific third-party plugin are not this project's
266
- to publish.
89
+ Committed evidence records a digest of each side rather than the results themselves, because findings about a specific third-party plugin are not this project's to publish.
267
90
 
268
91
  ## Documentation
269
92
 
270
93
  | Document | For |
271
94
  | --- | --- |
95
+ | [docs/INSTALL.md](docs/INSTALL.md) | install details, PATH, requirements, upgrading, and what Socket reports and why |
96
+ | [docs/HOW.md](docs/HOW.md) | what omakit is doing, why it uses Node, the baseline and check labels |
97
+ | [docs/COMMANDS.md](docs/COMMANDS.md) | command details, authentication and network behaviour |
272
98
  | [docs/SUBMIT.md](docs/SUBMIT.md) | every check and what it decides |
99
+ | [docs/WEIGH.md](docs/WEIGH.md) | what `weigh` measures, the noise floor, the `shell.json` mutation and its restore, and the JSON contract |
273
100
  | [docs/VALIDATION_WATCH.md](docs/VALIDATION_WATCH.md) | the validation watch: what the marketplace validated, and what moves it |
274
101
  | [docs/MEASUREMENTS.md](docs/MEASUREMENTS.md) | every number, its method and its limits |
275
102
  | [docs/UPSTREAM_CONTRACT.md](docs/UPSTREAM_CONTRACT.md) | the seam, the pin, the boundaries |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "omakit",
3
- "version": "0.1.9",
4
- "description": "The safe place to find out: everything knowable about an Omarchy Quattro plugin submission before you post it, on your own machine. Agent-first, read-only, posts nothing, zero dependencies.",
3
+ "version": "0.2.1",
4
+ "description": "The safe place to find out: everything knowable about an Omarchy Quattro plugin submission before you post it, on your own machine. Agent-first, read-only against the marketplace, posts nothing, zero dependencies.",
5
5
  "license": "MIT",
6
6
  "author": "Maarten Tolhuijs",
7
7
  "keywords": [
@@ -0,0 +1,102 @@
1
+ ---
2
+ name: omarchy-plugin-check
3
+ description: Check an Omarchy Quattro plugin while building or changing it, before committing or pushing. Use whenever you create, edit, refactor or test an Omarchy plugin, when asked whether a plugin is marketplace-ready, or before any push to its default branch. Runs the marketplace's own security baseline and submission checks locally, read-only, and reports what the marketplace would refuse.
4
+ ---
5
+
6
+ # Checking a plugin while you build it
7
+
8
+ ## Run this the way you run a test suite
9
+
10
+ After every meaningful change to an Omarchy plugin, run both, from the
11
+ plugin's repository root or with its path:
12
+
13
+ ```bash
14
+ omakit verify <path-to-the-plugin-repo> --json
15
+ omakit submit <path-to-the-plugin-repo> --category <category> --tags <a,b> --json --offline
16
+ ```
17
+
18
+ `verify` is the marketplace's own security baseline over this exact commit,
19
+ verbatim, with no Omakit check around it. `submit` is every pre-submission
20
+ check the marketplace applies, rendered from the marketplace's own form and
21
+ judged by the marketplace's own parser.
22
+
23
+ **Always pass `--category` and `--tags`.** A run without them asks a person
24
+ at a terminal, and an agent must never wait on a keyboard. If you do not know
25
+ the allowed values, run once without them in a pipe or with `--json`: that is
26
+ a usage error (exit 2) whose message lists the controlled values, read from
27
+ the pinned form. Pick the category and tags with the owner; they are an
28
+ editorial choice about where the plugin belongs.
29
+
30
+ `--offline` belongs in this loop and nowhere else: it skips the one check that
31
+ needs the network and reads the listed ids from the pin. For the real
32
+ submission, drop it, and use `skills/omarchy-plugin-submit/SKILL.md`.
33
+
34
+ ## If omakit is not installed
35
+
36
+ ```bash
37
+ npm install --global omakit # Omarchy ships Node and npm through mise
38
+ omakit doctor # node, git, the pin, the credential source, and whether omakit is on PATH
39
+ ```
40
+
41
+ If `omakit` is not found after the install, run
42
+ `"$(npm prefix --global)/bin/omakit" setup`: it prints the one line that puts
43
+ npm's bin on PATH for the shell in `$SHELL`. Keep it current with
44
+ `omakit upgrade`. The first `submit` or `verify` needs the pin: `omakit pin`
45
+ fetches a sparse read-only checkout of one marketplace commit under
46
+ `$XDG_CACHE_HOME/omakit/marketplace` (or `~/.cache/omakit/marketplace`).
47
+
48
+ ## Reading the result
49
+
50
+ `submit --json` ends with `outcome`:
51
+
52
+ - `ready`, exit 0: every blocking check passed. The plugin would be accepted
53
+ by the marketplace's automated checks as it is now.
54
+ - `refused`, exit 1: a blocking check failed. `blocking` lists the root
55
+ causes; each check carries `detail`, `paths`, `remedy` and `why`.
56
+ - `listed`, exit 0: the plugin is already listed by this repository.
57
+ `listing` names the reviewed commit and whether the local commit is it.
58
+
59
+ Each check has a `verdict`: `pass`, `fail`, `unknown` (it could not run
60
+ because a check it depends on failed; fix that one first) or `skipped` (not
61
+ run under `--offline`). `severity` is `blocking` or `advisory`; an advisory
62
+ check never turns `ready` into `refused`.
63
+
64
+ Each check names a `source`. `marketplace-pin` is the marketplace's own rule,
65
+ read from the pinned checkout. `omakit` is this tool's own check, derived
66
+ from public issue data with the measurement in `why`. Never describe an
67
+ `omakit` check to the owner as a marketplace requirement.
68
+
69
+ Fix the cause the remedy names. Do not work around a check, do not strip files
70
+ from the owner's tree on your own, and never change the plugin id to get past
71
+ `identity.available` when the listing is this repository's own.
72
+
73
+ ## What the baseline result means
74
+
75
+ `verify` and the `baseline.preflight` check report the official outcome:
76
+
77
+ - `passed`: nothing in the baseline holds the plugin back.
78
+ - `review-required`: no findings, but one or more of the seven capabilities is
79
+ present, so a maintainer must look at this exact commit. Not a defect; worth
80
+ explaining in the submission's `--notes` rather than hiding.
81
+ - `needs-fixes`: findings, each with a rule id, the file, and the marketplace's
82
+ own remedy text. Only `sudoers-dangerous-passwordless-command` and
83
+ `privileged-process-control-from-shared-temp` block publication under the
84
+ current enforcement mode; the rest a maintainer may accept for that commit.
85
+ Fixing them first avoids a human round either way.
86
+
87
+ Never restate any of this as a safety claim. The baseline performs no data-flow
88
+ analysis and is not a security review; the output says so in the marketplace's
89
+ own words, and so should you.
90
+
91
+ ## The commit rule
92
+
93
+ The marketplace validates the pushed default-branch HEAD, not whatever is
94
+ checked out locally. Run the check on the commit that will be pushed, then
95
+ commit and push before the real submission. Of the 464 submissions parked in
96
+ their author's court, 73% have a HEAD the marketplace never saw; that is the
97
+ round this loop is meant to prevent.
98
+
99
+ ## When the plugin is ready
100
+
101
+ Hand over to `skills/omarchy-plugin-submit/SKILL.md`. The owner decides
102
+ whether to submit, and you never open the issue yourself.
@@ -32,6 +32,10 @@ omakit pin # once, and after any pin change: fetches the pinned marketplace
32
32
  omakit submit <path-to-the-plugin-repo> --category <category> --tags <a,b>
33
33
  ```
34
34
 
35
+ While a plugin is still being built or changed, run the check loop in
36
+ `skills/omarchy-plugin-check/SKILL.md` instead; this skill is for the
37
+ submission itself.
38
+
35
39
  The pin is a sparse read-only checkout of one marketplace commit under
36
40
  `$XDG_CACHE_HOME/omakit/marketplace` (or `~/.cache/omakit/marketplace`). Every
37
41
  rule is read from it; nothing about the format is written in the tool.
@@ -0,0 +1,128 @@
1
+ ---
2
+ name: omarchy-plugin-weigh
3
+ description: Weigh an Omarchy Quattro plugin on the shell, in CPU and child processes, by restarting the shell without it and with it. Use before a submission, after a change that adds a timer, a process or a file watcher, or when asked how heavy a plugin is. Restarts the person's shell, so it must never run without their explicit agreement.
4
+ ---
5
+
6
+ # What a plugin weighs on the shell
7
+
8
+ ## The one thing to get right
9
+
10
+ **This command restarts the shell.** `omakit weigh` measures a plugin by
11
+ starting the person's `omarchy-shell` without the plugin and with it, several
12
+ times, and it edits `~/.config/omarchy/shell.json` for the duration. Every
13
+ other omakit command is read-only; this one is not. So:
14
+
15
+ - Never run it with `--yes` unless the person has just agreed, in this
16
+ conversation, to have their shell restarted that many times. The command
17
+ prints the count and the estimated minutes before it asks; put those in
18
+ front of the person and wait for their answer.
19
+ - Never run it while they are in the middle of something on that desktop.
20
+ The bar, every panel and every plugin go away and come back on each
21
+ restart, (1 + plugins) × runs times, and a restart costs about a minute
22
+ (a 30 s settle and a 15 s window after each). One plugin at three runs is
23
+ six restarts, about five minutes. `--all` is sized for a lab machine, not
24
+ a working desktop: 47 enabled plugins is 144 restarts and about two hours
25
+ at three runs, three and a half at five. Offer `--all` only for a machine
26
+ nobody is using.
27
+ - Never run it on your own machine's shell as a stand-in for theirs. The
28
+ weight is the weight on the machine the plugin runs on.
29
+
30
+ Without `--yes`, from a pipe or with `--json`, the command prints the plan
31
+ and refuses with `█ NOT WEIGHED` (exit 2); nothing is touched. That refusal
32
+ is the correct outcome of an agent running it unasked. The same word, with
33
+ one sentence naming what is missing, is how it refuses an Omarchy it cannot
34
+ weigh on: no `omarchy-shell` (an install older than the Quattro shell), no
35
+ `omarchy-restart-shell`, no readable version, a shell that does not answer
36
+ `ping`, or an IPC target without the four methods it relies on. Report that
37
+ sentence to the person as it is; do not work around it.
38
+
39
+ ## When to run it
40
+
41
+ - Before submitting: the README sentence it produces belongs in the
42
+ plugin's README, next to what the plugin does. The question a person
43
+ asks is how heavy it is; this answers it with a measurement.
44
+ - After a change that adds a `Timer`, a `Process`, a `FileView` with
45
+ `watchChanges`, a `SystemClock`, or a `Connections` to a busy service. A
46
+ declared interval says nothing about what runs; this measures it.
47
+ - When the owner asks how heavy the plugin is. Answer with the measured
48
+ figures and their noise floor, never with an estimate from the source.
49
+
50
+ ## Run it
51
+
52
+ ```bash
53
+ omakit weigh <plugin-id-or-dir> # one plugin, asks first
54
+ omakit weigh <plugin-id-or-dir> --yes --json # only after the person agreed
55
+ omakit weigh --all --yes # every enabled third-party plugin
56
+ ```
57
+
58
+ The plugin must be installed and enabled in the running shell: the
59
+ measurement puts it back exactly where the person has it. A plugin of kind
60
+ `bar` is refused (replacing the whole bar is not a weight), and so is a locked
61
+ session. `--runs` (default 3), `--window` (default 15 s) and `--settle`
62
+ (default 30 s) trade time for a lower noise floor; leave them at their
63
+ defaults unless the floor is too high to answer the question.
64
+
65
+ If `omakit` is not installed: `npm install --global omakit` (Omarchy ships
66
+ Node and npm through mise), then `omakit doctor`. `weigh` needs no pin and no
67
+ network.
68
+
69
+ ## Reading the verdicts
70
+
71
+ The header prints the **noise floor** once: the spread of the baseline's
72
+ own CPU across its runs. A plugin whose median CPU delta is not larger than
73
+ that floor has **no measurable CPU**, in those words, and the row is `ok`.
74
+ A row is `note` when CPU is above the floor, and `?` when no run of it
75
+ completed.
76
+
77
+ - `no measurable CPU` means the measurement cannot tell the plugin from
78
+ nothing at this run count and window. It does not mean zero. Say "no
79
+ measurable CPU against a floor of N%", with the number.
80
+ - `above noise on CPU` is a measured weight. Report the median and its
81
+ spread, and the children line separately: a plugin that adds 0.1% in the
82
+ shell and runs a 40 MB helper weighs both.
83
+ - **Memory is the shell's, not the plugin's, for now.** The memory delta is
84
+ printed with its spread, and the header labels it "within the shell's own
85
+ startup variance (N MB)". Never turn it into a sentence about the plugin
86
+ ("costs N MB", "under N MB"): the shell comes to rest on one of two
87
+ levels 35 MB apart after a restart, and that difference is not the
88
+ plugin's (`docs/MEASUREMENTS.md`, C1 and C2). If the owner asks about
89
+ memory, say exactly that and show the figure with the variance beside it.
90
+ - A negative median is printed as measured. Do not round it to zero and do
91
+ not explain it away; it means the delta is inside the noise.
92
+ - Never describe a weight as acceptable or unacceptable. The verdict is a
93
+ comparison with the floor; whether the number is fine is the owner's
94
+ call, made with the number in front of them.
95
+
96
+ In `--json`, each row carries `verdict.memory` and `verdict.cpu`
97
+ (`within-noise`, `above-noise`, `unknown`), `withinNoise` with the floors,
98
+ the stats objects (`median`, `spread`, `min`, `max`, `runs`), and `origin`
99
+ naming the `/proc` paths and the arithmetic. `config.md5Before` and
100
+ `config.md5After` must be equal and `config.restored` true; if they are not,
101
+ tell the person at once and name `config.backup`, which is kept. The full
102
+ contract is `docs/WEIGH.md`.
103
+
104
+ ## What to paste into the README
105
+
106
+ The last thing the command prints is the sentence, per plugin, and the path
107
+ of the JSON that is its evidence:
108
+
109
+ ```text
110
+ Weighs no CPU above the floor (0.13%) and runs 2 child processes using 8.2 MB and 0.1% CPU, on Omarchy 4.0.0.alpha, measured with omakit weigh on 2026-09-14
111
+ ```
112
+
113
+ Paste it as it is, under a heading such as "What it weighs", and keep the
114
+ JSON with the plugin's evidence or link to it. It names the CPU floor even
115
+ when the plugin is under it, and the child processes with their memory;
116
+ it never names the shell's memory, and neither should you in that README.
117
+ Re-run and replace the sentence after any change that adds a timer,
118
+ a process or a watcher; a sentence measured on an older commit is a claim
119
+ about a plugin that no longer exists.
120
+
121
+ ## What the measurement does not know
122
+
123
+ Per-plugin memory inside the shell is knowable only by this A/B, because Qt
124
+ allocates from shared heaps. RSS never falls when a plugin is unloaded and
125
+ every bar widget rebuilds on any layout change, so nothing here measures a
126
+ running shell before and after; both sides start fresh. The weight of a panel
127
+ only while it is open, and any weight that depends on another plugin, are not
128
+ measured. Do not extrapolate either.
@@ -28,12 +28,29 @@ local commit through the transport seam the marketplace tests itself
28
28
  | `report.mjs` | Text rendering of submit, watch, doctor and verify for the agent that runs this tool, and the person reading over its shoulder. |
29
29
  | `path-hint.mjs` | Is `omakit` reachable as a bare command, and if not, the one line that makes it so for the install that is here: a symlink for a clone, the npm prefix's `bin` on PATH for a package, said for the shell in `$SHELL`. `setup` and `doctor` print it; nothing writes an rc file. |
30
30
  | `usage.mjs` | The help text, as data. |
31
+ | `options.mjs` | Every option every command accepts, in one table, and the parser that reads a command line against it before anything runs; `tests/unit/options.test.mjs` holds the help signatures, and through them the completion scripts, to the table. |
31
32
  | `completion.mjs` | A completion script for bash, zsh or fish, derived from the help data and the pin's form: the subcommands and flags are read out of `COMMANDS`, the categories and tags out of the pinned submission form, and the script says which pin it came from. `setup` installs it for the shell in `$SHELL`, the one file this tool writes outside its own checkout. |
33
+ | `completion-check.mjs` | Whether tab completion actually works: a frozen probe per shell run interactively, asking the loader to load `omakit` the way TAB does; the one marked block `setup` may append to an rc file after a yes, looked for by its marker first; the installed script's version and pin read from its first line; `doctor`'s `omakit.completion`; and the once-a-day stale notice. |
32
34
  | `banner.mjs` | The wordmark, on a bare `omakit` and in `setup` only. |
33
35
  | `effect.mjs` | The one text effect: the wordmark through `ttfx` where it is drawn, with frozen arguments, a hard budget, no colour of its own, and nothing at all when `ttfx` is not there. |
34
36
  | `progress.mjs` | The progress line, on stderr, only when a person is looking. |
35
37
  | `paths.mjs` | Omakit's cache directory, following XDG, and `withHomeAbbreviated()`: a path under `$HOME` written as `~/...` for a person, applied where doctor, setup and pin render text and never where a result is built, so `--json` keeps every path absolute. |
36
- | `cli.mjs` | The one entry point behind `bin/omakit`, and the one register every failure is reported in. `submit` exits on the outcome: 1 for `refused`, 0 for `ready` and `listed`. |
38
+ | `cli.mjs` | The one entry point behind `bin/omakit`, and the one register every failure is reported in. `submit` exits on the outcome: 1 for `refused`, 0 for `ready` and `listed`. `weigh` confirms before its first restart and exits 130 when interrupted, after the restore. |
39
+
40
+ `tools/weigh/` is `omakit weigh`, the one command that changes the user's own
41
+ machine (docs/WEIGH.md):
42
+
43
+ | File | Purpose |
44
+ | --- | --- |
45
+ | `weigh/commands.mjs` | The frozen table of Omarchy commands the measurement runs (`omarchy-shell`, `omarchy-restart-shell`, `omarchy plugin list`, `omarchy-plugin-catalog`, `qs list`, the session-lock check, `systemctl --user show-environment`, `getconf`), and the one spawn call site under `tools/weigh/`. |
46
+ | `weigh/proc.mjs` | Reading `/proc`: `utime+stime` and `cutime+cstime` from `stat`, `VmRSS` from `status`, `Pss` from `smaps_rollup`, and a descendant walk by parent id, all against a root that tests point at a directory. |
47
+ | `weigh/config.mjs` | Where `shell.json` is, the pure transform that removes a set of plugin ids from the effective configuration, the byte-for-byte backup, the restore and its md5 verification. |
48
+ | `weigh/stats.mjs` | Median, spread, the stats object, and the within-noise comparison. |
49
+ | `weigh/audit.mjs` | `planWeigh()` reads and decides (what runs, how many restarts, the estimate) and writes nothing; `measureWeigh()` restarts, samples and restores in a `finally`; `buildDocument()` turns the samples into the document. |
50
+ | `weigh/contract.mjs` | The JSON contract of docs/WEIGH.md as a validator, run by the unit tests and by the lab over a real document. |
51
+ | `weigh/list.mjs` | `weigh --list`: every installed plugin with its last weighing from the documents under the state directory, read-only, unweighed enabled plugins first. |
52
+ | `weigh/report.mjs` | The confirmation and the report for a person, drawn with `style.mjs`; the README sentence and the evidence path come last. |
53
+ | `weigh/confirm.mjs` | The one question, at a terminal, on stderr. |
37
54
 
38
55
  ```text
39
56
  omakit pin