Skip to content

feat(omarchy): a bar widget that answers the one question no cloud plugin can (GDK-116) - #20

Merged
midagedev merged 1 commit into
mainfrom
feat/gdk-116-omarchy-plugin
Aug 18, 2026
Merged

feat(omarchy): a bar widget that answers the one question no cloud plugin can (GDK-116)#20
midagedev merged 1 commit into
mainfrom
feat/gdk-116-omarchy-plugin

Conversation

@midagedev

Copy link
Copy Markdown
Owner

Omarchy's plugin directory already has widgets for Jira, Linear, Todoist, ClickUp and Basecamp. Every one of them needs a cloud account, a token, and live network. Competing on "my assigned tickets" loses to all of them — and a standalone gadak workspace has no "me" at all, since init --standalone clears AccountID. So the widget shows the two numbers only a local mirror can answer offline:

open · stuck        368·201 on the demo snapshot

open is issues outside the done status category; stuck is those whose status_changed_at is older than seven days (a duration is deliberately not a stored column, so the threshold is computed in the query).

The data contract is the part that had to be right. The widget runs gadak sql --json and nothing else — it never opens gadak.db. The mirror is a disposable cache whose schema is explicitly not a contract; a plugin that opened it would break on a migration and would read a half-written file mid-sync. The query lives in one file (gadak/query.sql) that both the QML and the gate use, so the gate cannot pass on a string the widget does not run. The parser reads stdout only, because the stale-mirror warning goes to stderr and would otherwise be parsed as data.

Every failure state is legible, because the state a stranger sees first is "the plugin is installed and the binary is not":

state when
no gadak PATH miss — tooltip carries the tarball URL and asset names
not synced gadak ran, no mirror yet
sql err non-zero exit, or stdout that is not the expected NDJSON

Never an empty badge. Zero outbound network; one local command.

contrib/omarchy/verify.sh is the gate: manifest shape against the first-party clock manifest, no sqlite/gadak.db path anywhere in the plugin, no display-name filter, and the real query run against examples/demo.db asserting NDJSON with both keys and open > 0. FAIL-first: renaming the query's output columns gives missing key 'open' in {'broken_open': 368, …}, exit 1. qmllint is absent here, so that check skips with a printed reason instead of passing silently.

Premises the round corrected against the real sources (branch quattro): omarchy-plugin-clone only installs first-party ids and cannot install this, so install.sh copies into ~/.config/omarchy/plugins/<id>/ and enables; and issues_full on the demo snapshot is 534 rows, not 605 — 605 is items, which includes wiki pages.

Lead review changed two things in the QML. state was a declared property, but QQuickItem already owns that name and redeclaring it is a compile error we have no local qmllint to catch — it is now viewState. And the missing-binary test ran before the no-mirror test and matched a bare No such file or directory, so a plugin folder missing query.sql would have reported "no gadak": a broken install disguised as an absent binary.

I also cross-checked stuck by an independent expression (strftime('%Y-%m-%dT%H:%M:%S','now','-7 day') instead of julianday): both give 201, and 167 open issues have a NULL status_changed_at, correctly excluded rather than counted as stuck.

Not verified: no Omarchy machine has run this, and nothing has been submitted to the community directory.

🤖 Generated with Claude Code

…ugin can (GDK-116)

Omarchy's plugin directory already has widgets for Jira, Linear, Todoist,
ClickUp and Basecamp. Every one of them needs a cloud account, a token, and live
network. Competing on "my assigned tickets" would lose to all of them, and a
standalone gadak workspace has no "me" at all — `init --standalone` clears
AccountID. So the widget shows the two numbers that only a local mirror can
answer offline:

  open · stuck      368·201 on the demo snapshot

open is issues outside the done status category; stuck is those whose
status_changed_at is older than seven days. status_changed_at is deliberately
not a stored duration, so the threshold is computed in the query.

The data contract is the part that had to be right. The widget runs
`gadak sql --json` and nothing else — it never opens gadak.db. The mirror is a
disposable cache whose schema is explicitly not a contract; a plugin that opened
it would break on a migration and would read a half-written file mid-sync. The
query lives in one file (gadak/query.sql) that both the QML and the gate use, so
the gate cannot pass on a string the widget does not run. The parser reads stdout
only, because a stale-mirror warning goes to stderr and would otherwise be
parsed as data.

Every failure state is legible, because the state a stranger sees first is "the
plugin is installed and the binary is not":

  no gadak     PATH miss — tooltip carries the tarball URL and asset names
  not synced   gadak ran, no mirror yet
  sql err      non-zero exit, or stdout that is not the expected NDJSON

Never an empty badge. Zero outbound network; one local command.

contrib/omarchy/verify.sh is the gate: manifest shape against the first-party
clock manifest, no sqlite/gadak.db path anywhere in the plugin, no display-name
filter, and the real query run against examples/demo.db asserting NDJSON with
both keys and open > 0. FAIL-first: renaming the query's output columns gives
`missing key 'open' in {'broken_open': 368, ...}` and exit 1. qmllint is absent
here, so that check skips with a printed reason instead of passing silently.

Round premises the delegate corrected against the real sources (branch quattro):
omarchy-plugin-clone only installs first-party ids and cannot install this, so
install.sh copies into ~/.config/omarchy/plugins/<id>/ and enables; and
`issues_full` on the demo snapshot is 534 rows, not 605 — 605 is `items`, which
includes wiki pages.

Lead review changed two things in the QML. `state` was a declared property, but
QQuickItem already owns that name and redeclaring it is a compile error we have
no local qmllint to catch; it is now viewState. And the missing-binary test ran
before the no-mirror test and matched a bare "No such file or directory", so a
plugin folder missing query.sql would have reported "no gadak" — a broken
install disguised as an absent binary.

Not verified: no Omarchy machine has run this. Nothing here has been submitted
to the community directory.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@midagedev
midagedev merged commit 25ad707 into main Aug 18, 2026
7 checks passed
@midagedev
midagedev deleted the feat/gdk-116-omarchy-plugin branch August 18, 2026 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant