Omarchy: hey omarchy poll, the engine under the 37signals.hey bar plugin - #236
Omarchy: hey omarchy poll, the engine under the 37signals.hey bar plugin#236jeremy wants to merge 4 commits into
Conversation
basecamp/omarchy-hey-plugin is a Quickshell bar widget that shells out to hey for the Imbox; hey setup omarchy installed an inline hey-unread module in the same bar. Neither knew of the other, and both installed meant two HEY icons and two Imbox pollers in one slot. Decision: the CLI is the engine, the plugin is the face. One Imbox fetch serves the panel, the icon and the toasts. hey omarchy poll --limit N [--notify] replaces the hidden bar-status. It answers in the shape of hey box imbox --json, byte for byte, so the plugin's parser does not change; with --notify the same read diffs the unseen postings against the fingerprint file and sends at most one toast, under a flock because the shell builds its bar once per monitor and two instances poll at once. Errors are errors now -- logged out is the auth envelope the plugin turns into its sign-in button, a global config that cannot load is config_error, and a later page that fails fails the poll rather than handing the panel a short list to replace its last complete one (the toasts still get the pages that were read). A poll without --notify deletes the fingerprints, so toasts turned on by any route -- hey setup omarchy, the plugin's toggle, omarchy bar set -- start from a silent seed. hey setup omarchy no longer installs a bar module. It removes a legacy hey-unread on sight, reported as its own step, and configures the plugin's entry in shell.json instead: --notify sets notify true, --no-notify deletes the key, a plain run leaves it, and a legacy module's --notify carries over when the plugin has not been told either way. Without the plugin the step skips and says how to install it; setup never clones on the user's behalf. The TUI pushes omarchy-shell -q 37signals.hey refresh after every posting mutation and Screener decision, so the icon goes dark the moment a thread is archived instead of at the next poll. A no-op off Omarchy.
There was a problem hiding this comment.
Pull request overview
Makes hey omarchy poll the data and notification engine for the Omarchy HEY bar plugin.
Changes:
- Adds paginated Imbox polling, notification state, and cross-monitor locking.
- Migrates setup from the legacy inline bar module to plugin configuration.
- Pushes plugin refreshes after relevant TUI mutations and expands tests/docs.
Tip
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
.surface |
Registers the new command surface. |
README.md |
Documents plugin installation and setup. |
docs/omarchy.md |
Defines the plugin/CLI integration contract. |
internal/cmd/box.go |
Extracts shared box table rendering. |
internal/cmd/omarchy.go |
Migrates setup to plugin configuration. |
internal/cmd/omarchy_lock_other.go |
Adds non-Unix lock fallback. |
internal/cmd/omarchy_lock_unix.go |
Adds Unix poll serialization. |
internal/cmd/omarchy_lock_unix_test.go |
Tests lock serialization. |
internal/cmd/omarchy_notify.go |
Updates notification state handling. |
internal/cmd/omarchy_notify_test.go |
Updates notification/setup tests. |
internal/cmd/omarchy_poll.go |
Implements hey omarchy poll. |
internal/cmd/omarchy_poll_test.go |
Tests polling, pagination, and errors. |
internal/cmd/omarchy_test.go |
Tests plugin setup migration. |
internal/cmd/root.go |
Preserves configuration-load errors for polling. |
internal/tui/mail.go |
Refreshes the plugin after mail mutations. |
internal/tui/omarchy_refresh.go |
Adds Omarchy refresh IPC. |
internal/tui/omarchy_refresh_test.go |
Tests refresh behavior. |
internal/tui/screener.go |
Refreshes after Screener changes. |
tests/smoke/helpers_test.go |
Isolates smoke-test state. |
tests/smoke/omarchy_test.go |
Adds poll smoke coverage. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…n change The lock sidecar is no longer unlinked by non-notify polls -- a poller holding the old inode and one locking a fresh one would diff at once -- and state deletion happens under the lock. The bar plugin step says installed only when its notify setting changed; a legacy removal in the same pass is the bar indicator step's news. Stale bar-status fixture, smoke state dir cleanup, and the docs now say what is byte-identical (the data, not the envelope), which file is flocked, and that the toast's N counts arrivals.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2251fb0c20
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…te dir Without HOME and XDG_STATE_HOME (or with a relative XDG_STATE_HOME) the state path resolved into the working directory, where a non-notify poll would have deleted a bystander omarchy-poll.json and a notify poll written one. The poll now leaves fingerprints alone entirely in that case and the toasts stay off, as they do when the identity is unknown; save and remove refuse outright. The poll envelope carries hey box's breadcrumbs too.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d1f0f5f535
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| switch { | ||
| case !omarchyPollStateUsable(): | ||
| case !c.notify: | ||
| _ = removeOmarchyPollState() |
There was a problem hiding this comment.
Prevent in-flight notify polls from restoring disabled state
When per-monitor polls straddle disabling notifications, this deletion can finish while an older --notify poll is still fetching; that older poll subsequently takes the lock, observes no state, and silently writes a new seed. If notifications are re-enabled before another non-notifying poll runs, mail accumulated while they were off is compared against this resurrected seed and can be toasted, violating the documented silent re-enable behavior. Keep the disable decision ordered with in-flight notifying polls, for example with a persisted disabled generation/tombstone or a lock covering the relevant poll lifecycle.
Useful? React with 👍 / 👎.
| // The lock sidecar goes only here, at teardown: a live poller holding it | ||
| // would otherwise be left with an unlinked inode while the next poll | ||
| // locks a fresh one, and the two would diff at once. | ||
| _, _ = removeFileIfPresent(omarchyPollLockPath()) |
There was a problem hiding this comment.
Refuse to unlink a relative poll lock during teardown
With an absolute HOME but relative XDG_STATE_HOME, hey setup omarchy --remove passes its home check and removeOmarchyPollState() correctly refuses the unsafe state path, but this direct cleanup still resolves the lock path relative to the process working directory and unlinks it. Fresh evidence beyond the earlier state-path fix is this teardown-only bypass of the validated helper, which can delete an unrelated state/hey-cli/omarchy-poll.json.lock; only remove the sidecar after confirming the state directory is absolute.
Useful? React with 👍 / 👎.
|
Superseded by #243: |
What
basecamp/omarchy-hey-plugin(Jason, Rob) is a Quickshell bar widget that shells out toheyfor the Imbox;hey setup omarchyinstalled an inlinehey-unreadmodule in the same bar. Neither knew of the other — both installed meant two HEY icons and two Imbox pollers. Decision: the CLI is the engine, the plugin is the face. One Imbox fetch serves the panel, the icon and the toasts.hey omarchy poll --limit N [--notify](visible; replaces the hiddenbar-status, which never shipped). Same envelope ashey box imbox --json, byte for byte.--notifydiffs the unseen set against the fingerprint file and toasts at most once, under aflock(the shell builds its bar once per monitor, so two instances poll concurrently). Errors are errors:authenvelope when logged out,config_erroron an unloadable global config, a failed later page fails the poll (the toasts still get the pages that were read). A poll without--notifydeletes the fingerprints, so toasts turned on by any route — setup, the plugin's toggle,omarchy bar set— start from a silent seed.hey setup omarchyno longer installs a bar module. It removes a legacyhey-unread(own step, notify preference carried over to the plugin when the plugin is silent) and flipsnotifyon the plugin'sshell.jsonentry. No plugin →skippedwith the install command; setup never clones.omarchy-shell -q 37signals.hey refreshafter every posting mutation and Screener decision. No-op off Omarchy.tests/smoke/omarchy_test.go(pollmatchesbox imbox,--notifyseeds under an isolatedXDG_STATE_HOME, bad--limit).Companion plugin PR: basecamp/omarchy-hey-plugin
hey-cli-engine(draft, offplugin-design). Docs:docs/omarchy.mdrecords the decision and the new contract.Release note
Do not release 0.2.0 until the plugin repo is public and its PR is merge-approved — the README now points users at it.
Verified
make build && make test && make lint,make check-surface-compat(additions only:hey omarchy,hey omarchy poll --limit/--notify). Plugin:./tests/run(11 node + 15 QML) andomarchy plugin validategreen against this branch.Summary by cubic
Unifies HEY bar behavior: the CLI is the engine and the bar plugin is the face.
hey omarchy pollnow powers the37signals.heyplugin so one Imbox fetch drives the panel, icon, and toasts, eliminating duplicate icons and pollers.hey setup omarchyno longer installs a bar module. It removes a legacyhey-unreadon sight and configuresnotifyon the37signals.heyplugin if present; without the plugin it skips with install guidance.hey omarchy poll --limit N [--notify]returns the exacthey box imbox --jsondata shape; the response envelope also carriesboxbreadcrumbs. With--notify, it diffs unseen threads against fingerprints and toasts each at most once under an advisory read-only flock on a stable lock file; without--notify, it clears fingerprints under the same lock. If HOME/XDG_STATE_HOME does not resolve to an absolute state dir, the poll refuses to read/write state and skips notifications. Errors surface as envelopes:authwhen logged out,config_erroron an unreadable global config; a failed later page fails the poll (already-read pages may still toast).omarchy-shell -q 37signals.hey refreshafter posting mutations and Screener decisions.Review and rollout
internal/cmd/omarchy_poll.go(engine),internal/cmd/omarchy_lock_unix.go(serialized notify; lock inode stable),internal/cmd/omarchy_notify.go(state guarded and refuses relative dirs), and TUI refresh ininternal/tui/omarchy_refresh.go. Tests cover JSON parity withbox imbox, breadcrumbs, locking, and notify seeding.omarchy plugin add https://github.com/basecamp/omarchy-hey-plugin.git --enablehey setup omarchy --notifyor--no-notifybasecamp/omarchy-hey-pluginis public and its PR is approved; the README points to it.Written for commit d1f0f5f. Summary will update on new commits.