Parcel for Omarchy
Your Parcel deliveries in the Omarchy bar.

A bar badge shows how many parcels are on the way and lights up when one is out for delivery (or needs attention). Click it for a panel listing every active shipment with carrier, latest checkpoint and ETA; expand a row for the full timeline. When a parcel changes state you get a desktop notification.
Parcel is the iOS/macOS tracking app most of us already have on our phone. This plugin doesn't replace it — it reads the deliveries you've already added there through Parcel's Premium API, so your desktop and your phone agree.
Requires Omarchy Quattro (
omarchy-shell) and a Parcel Premium subscription — the API is a Premium feature. External dependencies are all part of a stock Omarchy install:curl,jq,secret-tool(libsecret),wl-copy(wl-clipboard) andflock(util-linux). No sudo, no packages to install, no changes to your configuration beyond the plugin's own entry inshell.jsonthatomarchy plugin enablewrites.
Install
omarchy plugin add https://github.com/zuccs/omarchy-parcel-app.git --enable
The widget lands in the right section of the bar. Move it with omarchy bar move.
Setup
-
Sign in at web.parcelapp.net and generate an API key (Settings → API).
-
Store it in your login keyring.
secret-toolprompts for the value so it never touches your shell history:secret-tool store --label='Parcel API key' service omarchy-parcel key api-key -
Press
rin the panel (or middle-click the badge). Until a key is stored the panel shows these same instructions with a copy button.
Verify from a terminal any time:
~/.config/omarchy/plugins/io.github.zuccs.parcel/bin/parcel-api status
~/.config/omarchy/plugins/io.github.zuccs.parcel/bin/parcel-api deliveries active | jq
Using it
| Where | Action |
|---|---|
| Badge — left click | Open / close the panel |
| Badge — middle click | Refresh now |
| Badge — right click | Open web.parcelapp.net |
Panel — ↑ ↓ / j k |
Move between deliveries |
Panel — Enter / Space / click |
Expand the checkpoint timeline |
Panel — y or c |
Copy the tracking number |
Panel — r |
Refresh now |
Panel — o |
Open web.parcelapp.net |
Panel — Tab / Shift+Tab |
Switch to the neighbouring bar panel |
Panel — Esc |
Close |
Bind a key in ~/.config/hypr/bindings.lua:
o.bind("SUPER + CTRL + SHIFT + P", "Parcel", "omarchy-shell shell toggle io.github.zuccs.parcel")
Uninstall
omarchy plugin remove io.github.zuccs.parcel
That removes the plugin directory and its shell.json entry. Two things are
yours and are left alone; clear them if you want a clean slate:
secret-tool clear service omarchy-parcel key api-key # the API key in your keyring
rm -rf ~/.local/state/omarchy/parcel # cached deliveries
If you added a keybind in ~/.config/hypr/bindings.lua, delete that line too.
Settings
Settings live inline on the widget's entry in ~/.config/omarchy/shell.json,
like every Omarchy bar widget. The defaults:
{ "id": "io.github.zuccs.parcel", "refreshIntervalSec": 600, "filterMode": "active", "notifications": "On", "hideWhenEmpty": "Off" }
| Key | Values | Meaning |
|---|---|---|
refreshIntervalSec |
300–3600 |
How often to poll. Floor is 300 s: Parcel allows 20 requests/hour and manual refreshes count. |
filterMode |
active / recent |
active shows parcels in progress; recent also includes recently delivered ones. |
notifications |
On / Off |
Desktop notification when a parcel changes state (e.g. goes out for delivery, or is delivered). |
hideWhenEmpty |
On / Off |
Hide the badge entirely when nothing is on the way. |
How it behaves
- Rate limits. The last good response is cached in
~/.local/state/omarchy/parcel/(mode0600). Opening the panel or restarting the shell reads the cache; only the timer and explicit refreshes hit the API. If Parcel returns 429 or the network is down, the cached data stays on screen with an "Offline — showing data from …" note. - Several monitors, one request. Each monitor's bar hosts its own copy of the
widget; the bridge serialises them with
flock, so they share one fetch and one set of notifications. - Notifications compare consecutive fetches: a parcel changing status is
reported; a parcel that drops out of the list is reported as no longer active
(Parcel's feed doesn't say whether it was delivered or removed — use
filterMode: "recent"if you want explicit Delivered transitions); a parcel seen for the first time is not reported (your phone already told you). - Theme-native. Colours, fonts, spacing and corner radius come from the shell's theme tokens, so it matches whatever Omarchy theme you switch to.
Privacy & security
- The only network endpoint is
https://api.parcel.app. The only file written is the response cache above. - Your API key lives in the login keyring (libsecret). It is never written to
shell.json, the QML never reads it, andbin/parcel-apihands it tocurlas a config on stdin (-K -) rather than as an argument, so it doesn't show up in the process list either. - Everything the API returns is treated as untrusted — it is relayed from
carrier systems, not written by Parcel. Response bodies are capped at 1 MiB
before anything parses them, delivery and event lists are capped before they
reach the panel, and every remote string is flattened to one bounded line of
plain text. Every
Textin the panel is pinned toText.PlainText, so no delivery description can turn into rich text and pull in a remote image. - The state directory sits at a predictable path, so the bridge treats it as
hostile: it refuses to use it if
omarchy/orparcel/is a symlink, takes its cross-monitor lock on the directory itself (there is no lock file to plant), writes caches only viarename(2), and reads them with a size cap and a timeout so a swapped-in FIFO or oversized file can't wedge the shell. A same-user process that races a cache swap between check and read can still make the bridge read a file — bounded, and a file that process could already read itself. bin/parcel-apiis ~425 lines of bash. Read it before you enable the plugin, as with any Omarchy plugin.
Development
# Install the normal way — the result is a plain git checkout you can edit in place.
omarchy plugin add https://github.com/zuccs/omarchy-parcel-app.git --enable
cd ~/.config/omarchy/plugins/io.github.zuccs.parcel
omarchy plugin validate .
qmllint -I "$OMARCHY_PATH/shell" *.qml # note: qmllint 1.0 rejects `function x(): void`, as it does on first-party Weather
node --test test/*.test.js # Model.js is plain JS and unit-tested
PARCEL_API_KEY=… bin/parcel-api deliveries active --max-age 0 | jq # bridge without a keyring
Saving files under ~/.config/omarchy/plugins/ hot-reloads most plugin kinds,
but bar-widget QML is currently cached until the shell restarts
(basecamp/omarchy#8555) —
run omarchy-restart-shell after editing BarWidget.qml or Panel.qml.
Layout:
manifest.json plugin identity, settings schema and defaults
BarWidget.qml bar entry point: badge + Loader for the panel
Panel.qml popup: fetch lifecycle, notifications, keyboard list
Model.js pure functions (parsing, sorting, ETA/relative time, diffs)
bin/parcel-api the only code that touches the network or the API key
data/carriers.json bundled carrier code → name snapshot; `bin/parcel-api carriers --refresh`
caches a newer list in ~/.local/state/omarchy/parcel/, which the widget
prefers on its next shell start
test/ node:test suite for Model.js
Roadmap
- Add a delivery from the panel: paste a tracking number, pick the carrier, done
(
bin/parcel-api addalready exists — Parcel allows 20 adds/day). - Optional Parcel-style route map for the expanded row.
License
MIT — see LICENSE. Not affiliated with Parcel or Omarchy.